web Development of Microservice Architecture Day05-SpringBoot

Keywords: Spring JSON Fragment SpringBoot

web Development of SpringBoot

Introducing projects

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

Internationalization of login pages

  • Internationalization: Writing Internationalization Profiles
    1. Write an internationalization profile and extract the internationalization messages that the page needs to display.
    2.SpringBoot automatically configures components for managing international resource files
    @Bean
    @ConfigurationProperties(
        prefix = "spring.messages"
    )
    public MessageSourceProperties messageSourceProperties() {
        return new MessageSourceProperties();
    }

	    @Bean
    public MessageSource messageSource(MessageSourceProperties properties) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        if (StringUtils.hasText(properties.getBasename())) {
        //setBasenames sets the internationalization resource file to remove the base name of the language country code.

 String basename = context.getEnvironment().getProperty("spring.messages.basename", "messages");	//Internationalized resource files can be placed directly under the classpath called messages.properties, or the basic name spring.messages.basename can be specified in the configuration file.
         
		messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(StringUtils.trimAllWhitespace(properties.getBasename())));
        }

        if (properties.getEncoding() != null) {
            messageSource.setDefaultEncoding(properties.getEncoding().name());
        }

        messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
        Duration cacheDuration = properties.getCacheDuration();
        if (cacheDuration != null) {
            messageSource.setCacheMillis(cacheDuration.toMillis());
        }

        messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
        messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
        return messageSource;
    }

3. Get internationalized values on the page

In the tag body:
th:text="#{}"
th:placeholder="#{}"
Unlabeled body, in-line expression
[[#{}]]
  • Internationalization Principle: Locale (Regional Information Object) in Internationalization; LocaleResolver (Obtaining Regional Information Object)
 @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(
            prefix = "spring.mvc",
            name = {"locale"}
        )
        // The default regional information parser is to obtain the local from the regional 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 has been modified during development, it is necessary to take effect in real time.
    1. Disable template engine caching - spring.thymeleaf.cache=false
    2. Compile ctrl+F9 after page modification
  • Display of Logon Error Message
th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"

Interceptor

  • Logon checks through interceptors

RESTful

  • Ordinary CRUD: URI, / Resource Name / Resource Identification
  • RESTful CRUD: Distinguishing CRUD operations on resources by HTTP requests
Ordinary CRUD (URI to differentiate 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 (to the modification page) emp/{id} GET
Go to the Add Page emp GET
Adding Employees emp POST
Go to the modification page (find out the employee information for display) emp/{id} GET
Modification of Employees emp/{id} PUT
Delete employees emp/{id} DELETE

thymeleaf Extraction of Elements from Public Pages

  • Extracting Common Fragments
<div th:fragment="copy">

</div>

- Introducing Common Fragments

<div th:insert="~{footer :: copy}"></div>

There are two ways to introduce public fragments:
~ {template ename:: selector} template name:: selector
 ~ {template ename:: fragment name} template name:: fragment name
 Where the template name (file name from a common fragment source) is parsed using the prefix and suffix configuration rule of thymeleaf
  • Introduce th attributes of common fragments:
    1.th:insert - inserts the entire public fragment into the element introduced by the declaration
    2.th:replace - Replace elements introduced by declarations with public fragments
    3.th:include - The content of the fragment to be introduced is included in this tag
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
  • When introducing public fragments using th attribute, you can write {} instead of {}, only in-line [[{}], [({})]

List CRUD

C:

  • Redirect: Represents redirect to an address / represents the current project path
  • forward: Represents forwarding to an address
  • Spring MVC automatically binds the request parameters to the attributes of the participating objects. The requirement is that the name of the request parameters should be the same as that of the attributes of the JavaBean participating objects.
  • Question: The data submitted is not in the right format: Birthday = Date formatting: Spring MVC converts the data submitted on the page to the specified type.

U:

  • Request URI and data id through + concatenation string
  • Pages send PUT requests:
    1. Configure Hidden HttpMethod Filter in Spring MVC to modify page requests. Spring Boot has been automatically configured.
    2. Page creates a POST form
    3. Create an input item, name="_method"; the value is the specified request method

Error handling mechanism

  • SpringBoot's default error handling mechanism
    1. When the browser visits, it returns a default error page: error status code, error type, error prompt system information, error time.
    The browser sends the request header: text.html.
    2. If accessed by other clients, return a default json data
    The client sends the request header:/*
    3. Principle: Refer to Error Mvc AutoConfiguration
    The following components were added to the container:
    DefaultErrorAttributes: Sharing 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. Basic Error Controller: Processing 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() {
        return this.errorProperties.getPath();
    }

    @RequestMapping(
        produces = {"text/html"}
    )	//Generate html data to process requests sent by browsers
    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 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 to 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);
    }

Error Page Customizer: Error Page Customizer: The system has 4-start and 5-start errors. This component takes effect and customizes error response rules. It will come to / error requests.

	@Value("${error.path:/error}")
    private String path = "/error";	//When the system has errors, the error request is processed

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, SpringBook can find 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, find the page corresponding to errorViewName under the static resource folder. If the static resource folder does not have the corresponding page, return to null.
        return provider != null ? new ModelAndView(errorViewName, model) : this.resolveResource(errorViewName, model);
    }

Error handling steps:
The system has errors at the beginning of 4 and 5. The component takes effect and customizes the error response rules. The request will come / error and will be processed by Basic Error Controller.
1. Response Page: Which page to go is parsed by 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 error pages
  • Template engine in some cases:
    1.error/Error Status Code, as long as the error page named "Error Status Code. html" is placed under the error folder in the template engine folder, the error of this status code will come to the corresponding page.
    2. You can use 4xx and 5xx as the file names of error pages to match all errors of this type - Precise Priority, that is, to find the exact error status code. html first.
    3. What information can the page get?
    timstamp: Time stamp
    Status: status code
    error: error prompt
    exception: exception object
    Message: Exception message
    Error: JSR303 Data Check Error
  • In the absence of a template engine:
    1. The template engine can't find the error page, just look under the static resource folder.
  • In the absence of template engine and static resource folders:
    1. Come to SpringBoot's error prompt page by default
    - How to customize the wrong json data:
    1. Customize exception handling and return custom json data
@ControllerAdvice
public class MyExceptionHandler {	//No adaptive effect - both browsers and clients 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. Forwarding 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<>();
        // Pass in your own error status code, otherwise you won't go into the analysis process of customized error page - --- Integer status Code = 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());
        //Forwarding to/error to achieve adaptive effect
        return "forward:/error";

    }
}

3. Carry out customized data: When an error occurs, the request comes to / error, which is processed by BasicErrorController, and the response data is obtained by getErrorAttributes (the method specified by AbstractErrorController).

  • You can write a subclass implementation class that inherits AbstractErrorController and put it in a container
  • Data available on pages and returned on json are all processed through errorAttributes.getErrorAttributes, which is DefaultErrorAttributes.getErrorAttributes() in containers.
  • The response is adaptive, and you can customize Error Atrributes to change what you want to return.
@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 handlers
        Map<String,Object> ext=(Map<String, Object>) webRequest.getAttribute("ext",0);
        map.put("ext",ext);
        return map;
    }
}

Posted by litebearer on Tue, 06 Aug 2019 04:15:00 -0700