Web development for SpringBoot

  • The introduction of the project
  • Internationalization of the login page
  • The login
  • The interceptor
  • RESTful
  • Thymeleaf extracts public page elements
  • List the CRUD
  • Error handling mechanism

The introduction of the project

  • Place your HTML pages in the Templates engine folder to take advantage of the template engine’s capabilities.

Internationalization of the login page

  • Internationalization: Write an internationalization profile. 1. Write an internationalization profile and extract the internationalization messages to be displayed on the page. 2

    @Bean
    @ConfigurationProperties( prefix = "spring.messages" )
    public MessageSourceProperties messageSourceProperties(a) {
        return new MessageSourceProperties();
    }

	@Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
    	/* * ResourceBoundleMessageSource extends AbstractResourceBasedMessageSource implements BeanClassLoaderAware * This implementation class allows the user to specify a resource name via beanName: a fully qualified resource name * that includes the classpath or a set of resource names */ via beanName
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
        /* * setBasenames setBasenames setBasenames setBasenames setBasenames setBasenames * the internationalization resource file can be placed directly in the classpath called messages.properties, or you can specify the basename spring.messages.basename */ in the configuration file
	    String basename = context.getEnvironment().getProperty("spring.messages.basename"."messages"); messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasen ame()))); }if(properties.getEncoding() ! =null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }
		/* * Return system locale if no locale-specific file is found * defaults to true * If off, a unique default file will be used: message.properties */ for baseName's "message"
        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if(cacheDuration ! =null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }
		/* * sets whether the MessageFormat component is always applied, parsing messages without arguments * for example :MessageFormat wants single quotes to be escaped to """, * If the message text is written entirely with this escape, this flag needs to be set to true * even if no parameter placeholders are defined; otherwise, only meaningful parameter message text will be written with MessageFormat escape */
        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        /* * Whether to use the message code as the default message instead of throwing NoSuchMessageException, * for development and debugging, the default value is false */
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }
Copy the code

MessageSource resolution:

  • MessageSource Architecture diagram:

    • MessageSource: Abstract message interface

    • HierarchicalMessageSource: layered source interface, can obtain the parent sources

    • MessageSourceSupport: Abstract class for message source parsing that formats messages by specifying the “message formatting component MessageFormat”

    • DelegatingMessageSource: Message source resolves the delegate class. When the user does not specify a message source resolution class,SpringContext uses this class by default. The functionality is simple: format the string and parameter array into a message string

    • AbstractMessageSource: Abstract class that supports “configuration file” internationalization of resources. Internally provides a common message configuration file independent of locale, with message codes as keywords

    • StaticMessageSource: Primarily for application testing. Allows you to provide internationalization information programmatically

    • ResourceBundleMessageSource: the implementation class allows the user to specify a resource through beanName name, including the fully qualified class names. Or specify a set of resource names by beanName. Different regions obtain and load different resource files to achieve the purpose of internationalization

    • ReloadableResourceBundleMessageSource:

      • The difference between ReloadableResourceBundleMessageSource and ResourceBundleMessageSource:

        • Type and method of loading resources:

          • ReloadResourceBundleMessageSource relying on Spring ResourceLoader loading Resource resources, more powerful, support. The class and the properties file
          • ResourceBundleMessageSource relying on the JDK’s own ResourceBundle load resources, supporting the absolute path, path and engineering support. The class and the properties file
        • Cache time:

          • ReloadResourceBundleMessageSource every loading record each resource loading time point, after the expiration cache resources will compare file modification time again, if the same does not need to be loaded, at the same time to refresh the loading point in time
          • ResourceBundleMessageSource mainly USES ResourceBundle. Simple Control to realize automatic loading
        • Encoding mode:

          • ReloadResourceBundleMessageSource not only can specify a default encoding, also support the encoding for each file separately

MessageSource interface:

methods describe
String getMessage(String code, Object[] args, String defaultMessge, Locale locale) Gets the message, and returns the default if no message is found
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException Gets the message, and if it cannot be found, it is treated as an error
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException Try parsing the message using all the attributes contained in the {@code MessageSourceResolvable} parameter passed in. A {@code NoSuchMessageException} must be thrown on this method because there is no way to determine if the resolvable {@code defaultMessage} property is empty when this method is called

MessageSourceResolvable wrapper interface and class for parsing message elements:

methods describe
String[] getCode() Returns the code used to resolve this message in the order in which it should be attempted. Therefore, the last code will be the default code
Object[] getArguments() Returns an array of parameters to be used to parse the message
String getDefaultMessage() Returns the default message to be used to parse this message

HierarchicalMessageSource source layer interface:

methods describe
void setParentMessageSource(MessageSource parent) The parent parameter that will be used to resolve messages that the secondary object cannot parse is the parent MessageSource that will be used to resolve messages that this object cannot parse. It could be {@code null}, in which case there is no need to solve
MessageSource getParentMessageSource() Returns the parent of the current MessageSource, otherwise {@code null}

MessageSourceSupport Abstract class used to support message source resolution:

methods describe
void setAlwaysUseMessageFormat(boolean alwaysUseMessageFormat) Sets whether the message format component is always applied and parses messages without parameters such as: MessageFromat expects the single quote to be escaped as “”” “If the message text is written entirely with this escape, you just need to set this flag to “true” even if no parameter placeholders are defined otherwise, only message text with actual parameters will be written using 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 locale) Renders the given default message string
String formatMessage(String msg, Object[] args, Locale locale) Renders the given message string
MessageFormat createMessageFormat(String msg, Locale locale) Create a MessageFormat for the given message and locale

DelegatingMessageSource Message source resolves the delegate class:

methods describe
String getMessage(String code, Object[] args, String defaultMessage, Locale locale) Parent message parsing If the parent message parsing source is not null, the parent message parsing source is used. Otherwise, use your own message source to parse the message
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException Message parsing If the parent message parsing source is not NULL, the parent message parsing source is used. Otherwise, an exception is thrown
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException Message parsing If the parent message parsing source is not null, the parent message parsing source is used. Otherwise, the parent message parsing source is used

AbstractMessageSourc abstract class AbstractMessageSourc abstract class

methods describe
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 locale) Parses the given code and arguments into messages set in the given locale, returning {@code null} if none is found.
String getMessageFromPArent(String code, Object[] args, Locale locale) Attempts to retrieve a given message from the parent MessageSource if there is one
String getDefaultMessage(String code) Return the default message
Object[] resolveArgements(Object[] args, Locale locale) The MessageSourceResolve object is found and parsed by searching the given parameter array
String resolveCodeWithoutArguments(String code, Locale locale) Parses a message with no parameters

StaticMessageSource Is AbstractMessageSource that allows you to programmatically provide internationalization information:

methods describe
void addMessage(String code, Locale locale, String msg) Associate a given message with a given code
void addMessage(Map<String, String> messages, Locale locale) Batch associates a given message with a given code

ResourceBundleMessageSource is AbstractMessageSource implementation class, allows the user to specify a resource through beanName – including the class path of the fully qualified name, or by beanNames specifies a set of resources:

methods describe
void setBaseName(String basename) Setting up resource files
Void setBaseNames (String… basenames) Set resource files in batches
void setDefaultEncoding(String defaultEncoding) Sets the default character set used to parse binding resource files
void setFallBackToSystemLocale(boolean fallbackToSystemLocale) Return to system locale if no locale-specific files are found Default is true. If false, the only alternate file will be the default file
void setCacheSeconds(int cacheSeconds) Sets the number of seconds for the cache to load the bound resource file
String resolveCodeWithoutArguments(String code, Locale locale) Parse the given message code into a key in the registered resource bundle, returning the value in the bundle as is, without using MessageFormat parsing
MessageFormat resolveCode(String code, Locale locale) Parse the given message code into a key in the registry resource bundle, each message code using a cached MessageFormat instance
ResourceBundle getResourceBundle(String baseName, Locale locale) Returns a ResourceBundle for the given baseName and code, extracting the generated MessageFormat from the cache
ResourceBundle doGetBundle(String baseName, Locale locale) throws MissingResourceException Gets the resource bundle for the given baseName and locale Settings
MessageFormat getMessageFormat(ResourceBundle resourceBundle, String code, Locale locale) throws Missing ResourceException Return a MessageFormat for the given package and code, extracting the generated MessageFormats from the cache
String getStringOrNull(ResourceBundle resourceBundle, String key) Gets the value corresponding to the specified key in the resource bundle

ReloadableResourceBundleMessageSource through beanName implementation class allows the user to specify a resource name, including the class path and fully qualified name. Or specify a set of resource names via beanNames:

methods describe
String resolveCodeWithoutArguments(String code, Locale locale) The message code is parsed into the key in the retrieved package file, and the value found in the package is returned as-is, without using MessageFormat parsing
MessageFormat resolveCode(String code, Locale locale) Parse the given message code into a key in the retrieved package file, each message code using a cached MessageFormat instance
PropertiesHolder getMergedProperties(Locale locale) Gets the holding Properties object for the locale
List< String > calculateAllFilenames(String basename, Locale locale) Computing all file names for a given bundle base name and locale will compute the file name for the given locale, the default file for system locale
List < String > calculateFilenamesForLocale(String basename, Locale locale) Computes the filename of the given bundle base package name and locale
Properties loadProperties(Resource resource, String filename) Parse the given Resource resource and return the corresponding Properties object
void clearCache() Clear the properties files corresponding to all resource bundles
void clearCacheIncludingAncestors() Clears the current MessageSource and the cache of all parent resources
  • MessageFormat Message component formatting: Mainly formats message strings and parameters into strings

3. Obtain the internationalized value on the page

Tags in the body: th: text = "# {}" th: placeholder = "# {}" the label mass, inline expression [[# {}]]Copy the code
  • Principles of internationalization: Locale(regional information object) in internationalization; LocaleResolver(Get region information object)
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty( prefix = "spring.mvc", name = {"locale"} )
        // The default Locale parser gets the Locale in the request header for internationalization parsing
        public LocaleResolver localeResolver(a) {
            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());
                returnlocaleResolver; }}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 {
                    returndefaultLocale ! =null? defaultLocale : requestLocale; }}else {
                returnrequestLocale; }}}Copy the code

The login

  • 1. Disable the template engine cache -spring.thymeleaf.cache=false 2. CTRL +F9 to recompile the page after modification
  • Display of login error messages
th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"
Copy the code

The interceptor

  • Login check via interceptor

RESTful

  • Plain CRUD: URI, / resource name/resource ID
  • RESTful CRUD: Identifies CRUD operations on resources using HTTP requests
Plain CRUD (URIs to distinguish operations) RESTful CRUD
The query getEmp Emp – GET
add AddEmp? xxx Emp – POST
Modify the UpdateEmp? id=xx&xxx Emp / {id} – PUT
delete DeleteEmp? id=xx Emp / {id} – DELETE
  • For example:
The request URI Request way
Query all employees emps GET
Query an employee (go to the Modify page) emp/{id} GET
Enter the Add page. emp GET
Add employees emp POST
Enter the modify page (check the employee information and display it) emp/{id} GET
Modify the employee emp/{id} PUT
Delete staff emp/{id} DELETE

Thymeleaf extracts public page elements

  • Extract common snippets
<div th:fragment="copy">

</div>
Copy the code
  • Introducing public fragments
<div th:insert="~{footer :: copy}"></div>There are two ways to introduce public fragments: ~ {templatename: : the selector} template name: : selector ~ {templatename: : fragmentname} template name: : fragments The template name (public segment the source file name) will use thymeleaf suffix configuration rules before parsingCopy the code
  • Th :insert – Inserts the entire public fragment into the element introduced by the declaration. Th :replace- replaces the element introduced by the declaration with the public fragment. Th :include- includes the contents 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>
Copy the code
  • When using th attributes into segments of the public, can need not write ~ {}, only inline writing [[~ {}]], [({}) ~] to write

List the CRUD

C:

  • Redirect: Redirects to an address/represents the current project path
  • Forward: forwards the packets to an address
  • SpringMVC automatically binds the request parameters to the properties of the input object one by one. The requirement is that the name of the request parameter is the same as the property name of the JavaBean input object.
  • Problem: The submitted data is not formatted properly: date of birth == date formatting :SpringMVC will need to convert the data submitted by the page to the specified type.

U:

  • Request URI and data ID through + concatenation string
  • The page sends a PUT request: 1. Configure HiddenHttpMethodFilter in SpringMVC to modify the page request. SpringBoot has been automatically configured 2. Create an input item,name=”_method”; Value is the specified request mode

Error handling mechanism

  • SpringBoot’s default error handling mechanism 1. When a browser accesses the SpringBoot, a default error page is displayed: error status code, error type, error message, and error time. 2. If other clients are accessing the browser, return the default JSON data header for the client to send the request :/* 3. Principle: can consult ErrorMvcAutoConfiguration to container to add the following components: 1. DefaultErrorAttributes: sharing error message 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;
    }
Copy the code

2.BasicErrorController: Handles default /error requests

@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(a) {
        return this.errorProperties.getPath();
    }

    @RequestMapping( produces = {"text/html"} )	
    // Generate HTML data to process requests 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);
        returnmodelAndView ! =null ? modelAndView : new ModelAndView("error", model);
    }

    @RequestMapping	// Generate JSON data to handle 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);
    }
Copy the code

3.ErrorPageCustomizer: If an error starting with 4 or 5 occurs, the component takes effect and customizes error response rules. That brings us to the /error request.

	@Value("${error.path:/error}")
    private String path = "/error";	// The system has an error request
Copy the code

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 be found on the page -error/404
        String errorViewName = "error/" + viewName;
        If the template engine can parse the page address, use the template engine to parse 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, look for the page corresponding to errorViewName in the static Resources folder. Returns null if the static resource folder has no corresponding page
        returnprovider ! =null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
    }
Copy the code

Error handling procedure:

  • If an error starting with 4 or 5 occurs, the component takes effect and customizes the error response rule. It will come to the /error request, and it will be handled by the BasicErrorController.
  • Response page: Which page to go to is resolved by TerrorViewResolver
 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;
    }
Copy the code
  • How do I customize the error response

    • How do I customize the error page

      • Error/error status code, as long as the error page named “error status code. HTML” in the template engine folder under the error folder, the occurrence of this status code error will be sent to the corresponding page 2. You can use 4xx and 5xx as error page filenames to match all errors of this type – precision first, that is, finding exact error status codes is preferred. HTML 3. What information can a page get:

        • Timstamp: time stamp
        • Status: status code
        • Error: indicates an error message
        • Exception: exception object
        • “Message” : abnormal message
        • Errors: indicates JSR303 data verification errors
      • If the template engine does not exist: 1. If the template engine cannot find the error page, search for it in the static resources folder

      • 1. By default, the SpringBoot error page is displayed

    • How to customize wrong JSON data: 1. Custom exception handling and return custom JSON data

@ControllerAdvice
public class MyExceptionHandler {	// There is no adaptive effect - both the browser and the 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());
        returnmap; }}Copy the code

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

@ControllerAdvice
public class MyExceptionHandler {
    @ExceptionHandler(RuntimeException.class)
    public String handleException(Exception e, HttpServletRequest request){
        Map<String,Object> map=new HashMap<>();
        // enter your own error statusCode. Otherwise, the custom error page will not be parsed --------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"; }}Copy the code

3. Carry custom data out: When an error occurs, a /error request is made which is handled by BasicErrorController and responds to data compiled by getErrorAttributes(Defined by AbstractErrorController(ErrorCont) Roller) prescribed method) get

  • You could write an implementation class that subclasses AbstractErrorController and put it in a container
  • Can use the data on a page, the json data is returned by errorAttributes. GetErrorAttributes, namely the container DefaultErrorAttributes. GetErrorAttributes () for data processing
  • The response is adaptive and you can change what needs to be returned 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 the exception handler
        Map<String,Object> ext=(Map<String, Object>) webRequest.getAttribute("ext".0);
        map.put("ext",ext);
        returnmap; }}Copy the code