二. 手寫SpringMVC框架
- 2022 年 4 月 5 日
- 筆記
- SpringMVC框架
1.1 新建DispatcherServlet
1.2 在src目錄下,新建applicationContext.xml
<?xml version=”1.0″ encoding=”UTF-8″?>
<beans id=”b1″>
<bean id=”emp” class=”xxx.controller.EmpController”/>
<bean id=”dept” class=”xxx.controller.DeptController”/>
</beans>
1.3 在DispatcherServlet的構造方法中解析applicationContext.xml配置文件
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@WebServlet(“*.do”)
public class DispatcherServlet extends HttpServlet {
private Map<String, Object> map = new ConcurrentHashMap<>();
public DispatcherServlet() {
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(“applicationContext.xml”);
// 1,通過工廠模式,創建documentBuilderFactory工廠對象
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
// 2,創建DocumentBuilder對象
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
// 3,得到Document對象( 注意導入org.w3c.dom包中的)
Document document = documentBuilder.parse(inputStream);
// 4,獲得所有的bean標籤
NodeList nodeList = document.getElementsByTagName(“bean”);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if(node.getNodeType() == Node.ELEMENT_NODE) {
//(注意導入org.w3c.dom包中的)
//強轉成Element類的對象,裡面有比Node類更方便的方法
Element element = (Element)node;
String id = element.getAttribute(“id”);
String className = element.getAttribute(“class”);
boolean flag = map.containsKey(id);
if(flag == true)
return;
Object o = Class.forName(className).newInstance();
map.put(id, o);
}
}
} catch (ParserConfigurationException | SAXException | IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 設置編碼
request.setCharacterEncoding(“UTF-8”);
response.setCharacterEncoding(“UTF-8”);
response.setContentType(“text/html;charset=UTF-8”);
// 假設url是: //localhost:8080/mymvc2/hello.do
// ServletPath是Servlet的訪問路徑: /hello.do
// 思路是:
// 第1步: /hello.do -> hello 或者 /book.do -> book
// 第2步: hello -> HelloController 或者 book -> BookController
String servletPath = request.getServletPath(); // /hello.do
int lastDotIndex = servletPath.lastIndexOf(“.do”);
servletPath = servletPath.substring(1, lastDotIndex); // hello
}
}
1.4 在DispatcherServlet的service方法中,通過ServletPath獲取對應的Controller對象,優化反射的程式碼
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 設置編碼
request.setCharacterEncoding(“UTF-8”);
response.setCharacterEncoding(“UTF-8”);
response.setContentType(“text/html;charset=UTF-8”);
// 假設url是: //localhost:8080/mymvc2/hello.do
// ServletPath是Servlet的訪問路徑: /hello.do
// 思路是:
// 第1步: /hello.do -> hello 或者 /book.do -> book
// 第2步: hello -> HelloController 或者 book -> BookController
String servletPath = request.getServletPath(); // /hello.do
int lastDotIndex = servletPath.lastIndexOf(“.do”);
servletPath = servletPath.substring(1, lastDotIndex); // hello
// 通過ServletPath獲取對應的Controller對象
Object xxxController = map.get(servletPath);
String ac = request.getParameter(“ac”);
System.out.println(“=======” + ac + “======”);
if (StringUtil.isEmpty(ac))
ac = “index”;
try {
// 這裡只能try…catch異常,因為在重寫的方法里,不能拋出比父類更大的異常
Method method = xxxController.getClass().getDeclaredMethod(ac, HttpServletRequest.class,HttpServletResponse.class);
if (method != null) {
method.invoke(xxxController, request, response);
} else {
throw new RuntimeException(“ac值違法“);
}
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
e.printStackTrace();
}
}
1.5 寫一個簡單的EmpController
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EmpController {
public void index(HttpServletRequest request,HttpServletResponse response) {
System.out.println(“EmpController…index”);
}
}
2. 第二次改進,每一個方法中都有獲取參數的程式碼, 或者都有請求轉發或是重定向的程式碼。解決跳轉問題
(程式碼格式問題各位大佬別吐槽,複製過來的有時間改)