Spring MVC principles
The Spring MVC principle is shown in the following figure
-
1. The user sends a request to the DispatcherServlet of the front-end controller
-
2. When DispatcherServlet receives a request, it invokes the HandlerMapping processor.
-
3. The processor mapper finds the specific processor based on the request URL, generates the processor object and the processor interceptor (if any) and returns it to the DispatcherServlet.
-
4. The DispatcherServlet invokes the handler through the HandlerAdapter processor adapter
-
A HandlerAdapter (also called a back-end controller) executes a handler.
-
6.Controller Returns to ModelAndView
-
7. The HandlerAdapter returns the handler execution result ModelAndView to the DispatcherServlet
-
8.DispatcherServlet passes ModelAndView to the ViewReslover view parser
-
9.ViewReslover parses and returns a specific View object
-
10. The DispatcherServlet renders the View (that is, populates the View with model data).
-
11.DispatcherServlet responds to user
The six components
-
DispatcherServlet: Front-end controller
When the user request reaches the front-end controller, it is equivalent to C in MVC mode. DispatcherServlet is the center of the whole process control, and it calls other components to handle the user’s request. The existence of dispatcherServlet reduces the coupling between components.
-
HandlerMapping: processor mapper
HandlerMapping is responsible for finding handlers according to user requests. Springmvc provides different mappers to implement different mapping methods, such as configuration files, implementation interfaces, annotations, and so on.
-
-Leonard: Handler?
Handler is the back-end controller following the Front-end controller of DispatcherServlet. Under the control of DispatcherServlet, the Handler processes specific user requests.
Because handlers involve specific user business requests, it is common for programmers to develop handlers based on business requirements.
-
HandlAdapter: Processor adapter
The processor is executed through a HandlerAdapter, which is an application of the adapter pattern, extending the adapter to execute on more types of processors.
-
View Resolver: View Resolver
The View Resolver is responsible for generating a View from the processing result. The View Resolver first parses the logical View name into the physical View name, i.e. the specific page address, and generates the View object. Finally, the View is rendered and the processing result is displayed to the user through the page.
-
View: View
The SpringMVC framework provides support for many View types, including jstlView, freemarkerView, pdfView, and more. The most common view we use is a JSP.
In general, it is necessary to display model data to users through page tags or page templates, and programmers need to develop specific pages according to business requirements.
In the various components of SpringMVC, the processor mapper, processor adapter, and view parser are called the three components of SpringMVC.
Components that need to be developed by users are: processors, views
The custom
1. First, the pom. XML file introduces the following dependencies:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.kkb</groupId>
<artifactId>springmvc-custom</artifactId>
<version>0.0.1 - the SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<! JSTL depends on whether the view object is a JSP -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<! -- servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<! -- Jackson dependency -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
<! -- DOM4J dependencies -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<! -- Xpath dependencies -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
<build>
<plugins>
<! Set Maven's JDK compile level
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8080</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
Copy the code
2. Compile the web. XML configuration file and configureDispatcherServlet
Front-end controller, as follows:
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="3.1">
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>com.kkb.springmvc.servlet.DispatcherServlet</servlet-class>
<! When Tomcat is started, the Servlet object is created.
<load-on-startup>2</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<! JSPS will not be intercepted, but static resources will be.
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Copy the code
3. The springmvc. XML configuration file is as follows:
<beans>
<! -- name attribute is URI -->
<! The class attribute is the full path of the processor class.
<bean name="/addUser" class="com.kkb.springmvc.handler.AddUserHandler" ></bean>
<bean name="/queryUser" class="com.kkb.springmvc.handler.QueryUserHandler" ></bean>
<! --HandlerAdapter -->
<bean class="com.kkb.springmvc.handleradapter.HttpRequestHandlerAdapter" ></bean>
</beans>
Copy the code
4. Customize the relationship of several important components in the Spring MVC framework as follows:
The front-end controller of DispatcherServlet is as follows:
/** * DispatcherServlet functions: 1: receives all request urls (except JSP requests) 2: dispatcher (request distribution) * 3: responds to processing results (returned to DispatcherServlet by the specific business handler) ** Thinks: Conclusion: We can use the delegate mode to delegate request lookup and request processing to different classes to handle specific solutions: * 1: a class that specifically searches the processor based on the request URL: processor mapper 2: a class that specifically executes the corresponding processor: Processor adapter * *@author huangshuai
*
*/
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 116714888769576151L;
private Map<String, Object> handlerMappings = new HashMap<>();
private List<HandlerAdapter> handlerAdapters = new ArrayList<>();
private static final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
// Get the initialization parameter in the servlet, springmVC.xml
String contextPath = config.getInitParameter(CONTEXT_CONFIG_LOCATION);
// Initialize the information in the Spring configuration file
initHandlerMapping(contextPath);
initHandlerAdapter(contextPath);
}
/** * Initializes the loading of HandlerAdapter **@param contextPath
*/
private void initHandlerAdapter(String contextPath) {
handlerAdapters = XmlUtils.getRequestAdapterFromXML(contextPath);
}
/*** * initializes loading HandlerMapping **@paramContextPath * Path of XML configuration file */
private void initHandlerMapping(String contextPath) {
// Use the utility class to read the XML configuration file to obtain the configuration information
handlerMappings = XmlUtils.getRequestMappingFromXML(contextPath);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
// Sets the character encoding of the request body
request.setCharacterEncoding("UTF-8");
// Get the request URL (URI is the parent of URL)
String uri = request.getRequestURI();
// Find the handler based on the URL
Object handler = getHandler(uri);
if (handler == null) {
/ / the response returned
}
// Find the corresponding processor adapter based on the processor
HandlerAdapter ha = getHandlerAdapter(handler);
if (ha == null) {
/ / the response returned
}
// Call the method of the processor for business processing: do not know the specific processor, cannot force, cannot call the method
// The adapter pattern is required here (for different classes or interfaces to be unified)
// The HandlerAdapter interface is designed to fit different processor classes. It is a unified class to facilitate method calls
// An adapter class is one processor type for each adapter class
ModelAndView mv = ha.handle(request, response, handler);
// Process the result
handleModelAndView(mv);
} catch(Exception e) { e.printStackTrace(); }}/** * process the return value **@param mv
*/
private void handleModelAndView(ModelAndView mv) {
// TODO Auto-generated method stub
}
/** * Get the corresponding processor adapter ** based on the found processor@param handler
* @return* /
private HandlerAdapter getHandlerAdapter(Object handler) {
for (HandlerAdapter ha : handlerAdapters) {
// Whether it fits
if (ha.supports(handler)) {
returnha; }}return null;
}
/** * Finds the processor object ** based on the request URL@param uri
* @return* /
private Object getHandler(String uri) {
return handlerMappings.get(uri);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response); }}Copy the code
5.HandlerAdapter
Processor adapters are as follows:
/** * Processor adapter * purpose: ADAPTS to different types of processors and enables DispatcherServlet to call different types of processors in a uniform way **@author huangshuai
*
*/
public interface HandlerAdapter {
/** * whether to use the processor *@param handler
* @return* /
boolean supports(Object handler);
/** * Execute successfully adapted processor *@param request
* @param response
* @paramHandler Successfully adapted to the processor *@returnReturn value of successful business processing *@throws Exception
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
Copy the code
HttpRequestHandlerAdapter processor adapter is as follows:
public class HttpRequestHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
if (handler instanceof HttpRequestHandler) {
return true;
}
return false;
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// This type of handler has no return value
((HttpRequestHandler)handler).handleRequest(request, response);
return null; }}Copy the code
SimpleControllerHandlerAdapter processor adapter is as follows:
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
if (handler instanceof Controller) {
return true;
}
return false;
}
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
ModelAndView modelAndView = ((Controller)handler).handleRequest(request, response);
returnmodelAndView; }}Copy the code
6.handler
The processor is as follows:
public interface Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Copy the code
/** * Make rules for writing processors *@author huangshuai
*
*/
public interface HttpRequestHandler {
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
Copy the code
The simple processor implementation class is as follows:
/*** * processor: specialized ** for handling different business requests@author huangshuai
*/
public class AddUserHandler implements HttpRequestHandler{
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Set the media type of the response body
response.setContentType("text/plain; charset=utf-8");
/ / response
response.getWriter().print("Added successfully"); }}Copy the code
/*** * processor: specialized ** for handling different business requests@author huangshuai
*/
public class QueryUserHandler implements HttpRequestHandler{
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Call the business method to process the business request
// Sets the character encoding of the request body
request.setCharacterEncoding("UTF-8");
// Set the media type of the response body
response.setContentType("application/json; charset=utf-8");
// Receive parameters
String id = request.getParameter("id");
if (id == null) {
/ / response
response.getWriter().print("Id parameter cannot be null");
return;
}
// Step 2: Call the business method
User user = new User();
user.setId(Integer.parseInt(id));
user.setUsername("zhangsan");
user.setAddress("Shangdi");
/ / responseresponse.getWriter().print(JsonUtils.object2Json(user)); }}Copy the code
/*** * processor: specialized ** for handling different business requests@author huangshuai
*/
public class QueryUserHandler2 implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// Receive parameters
String id = request.getParameter("id");
// Call the business layer method to process the business and return the processing result
User user = new User();
user.setId(Integer.parseInt(id));
user.setUsername("zhangsan");
user.setAddress("Shangdi");
// Return the result
ModelAndView mv = new ModelAndView();
mv.addAttribute("user", user);
mv.setViewName("");
returnmv; }}Copy the code
7.ModelAndView
As follows:
public class ModelAndView {
// Data model
private Map<String, Object> model;
// View name
private String viewName;
public ModelAndView(a) {
super(a);this.model = new HashMap<>();
}
public void addAttribute(String attributeName, Object attributeValue) {
model.put(attributeName, attributeValue);
}
public String getViewName(a) {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName; }}Copy the code
Utility classes for parsing XMLXmlUtils
As follows:
public class XmlUtils {
/** * Get HandlerMapping * Get the bean tag's class value (the full path of the class) based on the bean tag's ID */ use dom4J to parse the springmVC.xml configuration file */
public static Map<String, Object> getRequestMappingFromXML(String contextPath) {
Map<String, Object> requestMapping = new HashMap<>();
try {
// Create a SaxReader object
SAXReader reader = new SAXReader();
// Read the XML configuration file and return the Document object
Document document = reader.read(XmlUtils.class.getClassLoader().getResourceAsStream(contextPath));
// The XML is parsed through an xpath statement to get the class value of the bean label with the specified ID
//bean[@id='customerDao']
List<Element> selectNodes = document.selectNodes("//bean[@name]");
if (selectNodes == null || selectNodes.isEmpty()) {
return null;
}
for (Element element : selectNodes) {
// Get the request URI
String url = element.attributeValue("name");
// Get the full path of the corresponding processor class
String clazzName = element.attributeValue("class");
if(url ! =null && url.startsWith("/") && clazzName ! =null && !clazzName.equals("")) {
// Create a processor object with reflectionClass<? > clazz = Class.forName(clazzName); Object instance = clazz.newInstance();// Store the mapping between the URI and the processor object in the collectionrequestMapping.put(url, instance); }}}catch (Exception e) {
e.printStackTrace();
}
return requestMapping;
}
/** * get the HandlerAdapter */
public static List<HandlerAdapter> getRequestAdapterFromXML(String contextPath) {
List<HandlerAdapter> requestAdapter = new ArrayList<>();
try {
// Create a SaxReader object
SAXReader reader = new SAXReader();
// Read the XML configuration file and return the Document object
Document document = reader.read(XmlUtils.class.getClassLoader().getResourceAsStream(contextPath));
//bean[@id='customerDao']
List<Element> selectNodes = document.selectNodes("//bean");
if (selectNodes == null || selectNodes.isEmpty()) {
return null;
}
for (Element element : selectNodes) {
// Get the full path of the corresponding processor class
String clazzName = element.attributeValue("class");
if(clazzName ! =null && !clazzName.equals("")) {
// Create a processor object with reflectionClass<? > clazz = Class.forName(clazzName); Object instance = clazz.newInstance();// Store the mapping between the URI and the processor object in the collection
if (instance instanceofHandlerAdapter) { requestAdapter.add((HandlerAdapter)instance); }}}}catch (Exception e) {
e.printStackTrace();
}
returnrequestAdapter; }}Copy the code
The json utility JsonUtils class is as follows:
/** * JSON utility class (using Jackson's implementation) *@author huangshuai
*
*/
public class JsonUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
/** * convert the object to a JSON string. *@param data
* @return* /
public static String object2Json(Object data) {
try {
String string = MAPPER.writeValueAsString(data);
return string;
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
/** * Convert json result set to object **@paramJsonData JSON data *@paramObject type * in clazz objects@return* /
public static <T> T json2Pojo(String jsonData, Class<T> beanType) {
try {
T t = MAPPER.readValue(jsonData, beanType);
return t;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/** * Convert JSON data to poJO object list *@param jsonData
* @param beanType
* @return* /
public static <T>List<T> json2List(String jsonData, Class<T> beanType) {
JavaType javaType = MAPPER.getTypeFactory().constructParametricType(List.class, beanType);
try {
List<T> list = MAPPER.readValue(jsonData, javaType);
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null; }}Copy the code
9. Start project testing
Visit: http://localhost:8080/addUser
Spring MVC framework for kids is complete!!