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