Article directory
foreword
This series finally ushered in the writing of the second core function. First of all, we have three more important core functions in Spring. The first is our IOC inversion control DI dependency injection and of course the AOP aspect. In this part, we are already familiar with "Spring5 Core Principles and 30 Class Handwriting Practices", and we have implemented it according to cats and tigers, but we have not implemented the AOP part at this time, and today's part is the MVC part, to achieve our most One of the core functions is, of course, the simplest model, followed by database support. Then basically the three components are almost the same, then I will upgrade and maintain according to my own understanding (copying the real source code of Spring). Although our entire series, including this book, is actually more inclined to this idea, rather than looking at the source code directly, so first of all I think it will be confusing, I don't know why it is designed this way, then read the book first and see the big picture If you are a guy, you will have an understanding of this general idea, and then write it yourself, then think about why you wrote it like this, and then combine the actual source code to know how to optimize it.
Here, I recommend that you check out the first two blog posts beforehand.
Spring's handwritten SpringMVC5 annotations
Stick to the end of the article to get the warehouse address.
Process Review (MVC)
Before that, let's briefly review the processing flow of the first version for MVC, which is very important.
First of all, our MVC actually has two parts, one is our initialization part. The initialization part is divided into two parts, the first part is naturally our IOC part, and the second part is the part dedicated to our MVC.
After that is our dispatcher, which is the execution component of our MVC.
This is our original execution flow. Obviously, we found that the whole step can still be optimized, and we can also add components.
What is the most important point of MVC, obviously our view and model, view loading and data rendering.
Nine components of SpringMVC (understand)
Before we enter our content, we still need to briefly understand the nine components of our SpringMVC.
initMultipartResolver(context) 多文件上传组件
initThemeResolver(context) 初始化模板处理器
//mvc mapping组件(扫描mvc注解参数)
initHandlerMappings(context);
// 参数适配器,匹配参数执行方法
initHandlerAdapters(context);
initHandleExceptionResolvers(context) 异常拦截器
initRequestToViewNameTranslator(context) 初始化视图预处理器
// 初始化视图转换器
initViewResolvers(context);
//FlashMap处理器
initFlashMapManager(context);
So what we obviously want to achieve today is
initHandlerMappings(context);
initHandlerAdapters(context);
initViewResolvers(context);
new process
ok, back to us, since we are talking about optimization, then obviously we need to implement these three things, then obviously we need to do a little bit of processing on the current process.
initialization process
Here, we mainly discuss the process of the MVC part. As for the IOC, we will not pay attention to the DI part. The corresponding code is here
Component initialization
What did the initialization do?
You may be confused when you see this just now, so let me tell you what these three categories do.
See our flow chart directly here,
then the whole process is our initialization part.
Implementation process
After that is our execution process
. First of all, the first two are old friends, mainly what we did later, that is, our view parsing part, what did we do.
First of all, make it clear that our html file and the corresponding name have been encapsulated through initialization, which corresponds to our Model and View
. Then the model is the data we need to render. In this part, we need to pass our template. The engine does it.
And what parses all of this is our entry
, and then what this view will do for us is to parse the template
And the reason for this, in fact, one of the key tricks is still in our adapter
Then this is the core process of the entire MVC.
The point here is actually our encapsulated "information classes", those classes that encapsulate information.
"Information Class"
HUHandlerMapping
First of all, our handlermapping is naturally encapsulated. The corresponding method and corresponding url we scanned (here is a regular so it is actually a pattern) is followed by its controller.
HUModelAndView
This encapsulates the name of the view (you can understand it as html) and the data we need to render to the parser next.
Of course, it is matched with HUViewResolver
The relationship between HUViewResolver and HUModelAndView
In fact, as you can see from the name, the former actually helps us load the html file corresponding to the latter and send the data to be parsed to the template engine.
Parser HUView
The focus after that is our parser. The word here is the HUView class.
package com.huterox.spring.framework.webmvc.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HUView {
private File viewFile;
public HUView(File templateFile) {
this.viewFile = templateFile;
}
public void render(Map<String,?> model, HttpServletRequest req, HttpServletResponse resp) throws IOException {
StringBuffer sb = new StringBuffer();//最后输出的内容
RandomAccessFile ra = new RandomAccessFile(this.viewFile,"r");
String line = null;
while (null!=(line=ra.readLine())){
line = new String(line.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
Pattern pattern = Pattern.compile("\\$\\{[^\\}]+\\}",Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(line);
while (matcher.find()){
String paramName = matcher.group();
paramName = paramName.replaceAll("\\$\\{|\\}", "");
Object paramValue = model.get(paramName);
line = matcher.replaceFirst(makeStringForRegExp(paramValue.toString()));
matcher = pattern.matcher(line);
}
sb.append(line);
}
resp.setCharacterEncoding("UTF-8");
resp.getWriter().write(sb.toString());
resp.getWriter().flush();
}
public static String makeStringForRegExp(String str){
//特殊字符转移
return str.replace("\\","\\\\").replace("*","\\*")
.replace("+","\\+").replace("|","\\|")
.replace("{","\\{").replace("}","\\}")
.replace("(","\\(").replace(")","\\)")
.replace("^","\\^").replace("$","\\$")
.replace("[","\\[").replace("]","\\]")
.replace("?","\\?").replace(",","\\,")
.replace(".","\\.").replace("&","\\&");
}
}
The whole core is what our regular expressions
use to render the data.
test
ok, not much to enter the test link
data rendering ok
Project acquisition
Then the next step is to get our project. This time, I uploaded it directly to gitee, yes, directly to gitee