<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          手寫Spring框架之MVC

          共 7951字,需瀏覽 16分鐘

           ·

          2020-08-26 21:09


          簡介


          上一篇博客實現(xiàn)了Bean容器和IOC功能, 本篇博客來實現(xiàn)簡化版的 Spring MVC. 在看下面的內(nèi)容之前, 我們首先來回顧下 Spring MVC的架構(gòu)圖:




          Spring MVC 最核心部分的就是前端控制器DispatcherServlet, 而DispatcherServlet其實就是一個Servlet, 所以我們有必要先了解下Servlet的知識點, 如下:


          映射處理器


          (1) Request類


          請求類中的方法和路徑對應(yīng) @RequestMapping 注解里的方法和路徑.


          public?class?Request {
          ????/**
          ?????* 請求方法
          ?????*/

          ????private?String?requestMethod;

          ????/**
          ?????* 請求路徑
          ?????*/

          ????private?String?requestPath;

          ????public?Request(String?requestMethod, String?requestPath) {
          ????????this.requestMethod = requestMethod;
          ????????this.requestPath = requestPath;
          ????}

          ????public?String?getRequestMethod() {
          ????????return?requestMethod;
          ????}

          ????public?String?getRequestPath() {
          ????????return?requestPath;
          ????}

          ????@Override
          ????public?int hashCode() {
          ????????int result = 17;
          ????????result = 31?* result + requestMethod.hashCode();
          ????????result = 31?* result + requestPath.hashCode();
          ????????return?result;
          ????}

          ????@Override
          ????public?boolean?equals(Object?obj) {
          ????????if?(this?== obj) return?true;
          ????????if?(!(obj instanceof?Request)) return?false;
          ????????Request request = (Request) obj;
          ????????return?request.getRequestPath().equals(this.requestPath) && request.getRequestMethod().equals(this.requestMethod);
          ????}
          }


          (2) Handler類


          Handler類為一個處理器, 封裝了Controller的Class對象和Method方法.


          public?class?Handler?{

          ????/**
          ?????* Controller 類
          ?????*/

          ????private?Class controllerClass;

          ????/**
          ?????* Controller 方法
          ?????*/

          ????private?Method controllerMethod;

          ????public?Handler(Class controllerClass, Method controllerMethod)?{
          ????????this.controllerClass = controllerClass;
          ????????this.controllerMethod = controllerMethod;
          ????}

          ????public?Class getControllerClass() {
          ????????return?controllerClass;
          ????}

          ????public?Method getControllerMethod()?{
          ????????return?controllerMethod;
          ????}
          }


          (3) 實現(xiàn)映射處理器


          ControllerHelper 助手類定義了一個"請求-處理器" 的映射 REQUEST_MAP, REQUEST_MAP 就相當(dāng)于Spring MVC里的映射處理器, 接收到請求后返回對應(yīng)的處理器.


          REQUEST_MAP 映射處理器的實現(xiàn)邏輯如下:


          首先通過 ClassHelper 工具類獲取到應(yīng)用中所有Controller的Class對象, 然后遍歷Controller及其所有方法, 將所有帶 @RequestMapping 注解的方法封裝為處理器, 將 @RequestMapping 注解里的請求路徑和請求方法封裝成請求對象, 然后存入 REQUEST_MAP 中.


          public?final class?ControllerHelper?{

          ????/**
          ?????* REQUEST_MAP為 "請求-處理器" 的映射
          ?????*/

          ????private?static?final Map REQUEST_MAP = new?HashMap();

          ????static?{
          ????????//遍歷所有Controller類
          ????????Set> controllerClassSet = ClassHelper.getControllerClassSet();
          ????????if?(CollectionUtils.isNotEmpty(controllerClassSet)) {
          ????????????for?(Class controllerClass : controllerClassSet) {
          ????????????????//暴力反射獲取所有方法
          ????????????????Method[] methods = controllerClass.getDeclaredMethods();
          ????????????????//遍歷方法
          ????????????????if?(ArrayUtils.isNotEmpty(methods)) {
          ????????????????????for?(Method method : methods) {
          ????????????????????????//判斷是否帶RequestMapping注解
          ????????????????????????if?(method.isAnnotationPresent(RequestMapping.class)) {
          ????????????????????????????RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
          ????????????????????????????//請求路徑
          ????????????????????????????String requestPath = requestMapping.value();
          ????????????????????????????//請求方法
          ????????????????????????????String requestMethod = requestMapping.method().name();

          ????????????????????????????//封裝請求和處理器
          ????????????????????????????Request request = new?Request(requestMethod, requestPath);
          ????????????????????????????Handler handler = new?Handler(controllerClass, method);
          ????????????????????????????REQUEST_MAP.put(request, handler);
          ????????????????????????}
          ????????????????????}
          ????????????????}
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 獲取 Handler
          ?????*/

          ????public?static?Handler getHandler(String requestMethod, String requestPath) {
          ????????Request request = new?Request(requestMethod, requestPath);
          ????????return?REQUEST_MAP.get(request);
          ????}
          }


          前端控制器


          (1) Param類


          Param類用于封裝Controller方法的參數(shù).


          public?class?Param {

          ????private?Map<String, Object> paramMap;

          ????public?Param() {
          ????}

          ????public?Param(Map<String, Object> paramMap) {
          ????????this.paramMap = paramMap;
          ????}

          ????public?Map<String, Object> getParamMap() {
          ????????return?paramMap;
          ????}

          ????public?boolean?isEmpty(){
          ????????return?MapUtils.isEmpty(paramMap);
          ????}
          }


          (2) Data類


          Data類用于封裝Controller方法的JSON返回結(jié)果.


          public?class?Data?{

          ????/**
          ?????* 模型數(shù)據(jù)
          ?????*/

          ????private?Object model;

          ????public?Data(Object model)?{
          ????????this.model = model;
          ????}

          ????public?Object getModel()?{
          ????????return?model;
          ????}
          }


          (3) View類


          Data類用于封裝Controller方法的視圖返回結(jié)果.


          public?class?View {

          ????/**
          ?????* 視圖路徑
          ?????*/

          ????private?String?path;

          ????/**
          ?????* 模型數(shù)據(jù)
          ?????*/

          ????private?Map<String, Object> model;

          ????public?View(String?path) {
          ????????this.path = path;
          ????????model = new?HashMap<String, Object>();
          ????}

          ????public?View addModel(String?key, Object?value) {
          ????????model.put(key, value);
          ????????return?this;
          ????}

          ????public?String?getPath() {
          ????????return?path;
          ????}

          ????public?Map<String, Object> getModel() {
          ????????return?model;
          ????}
          }


          (4) RequestHelper 助手類


          前端控制器接收到HTTP請求后, 從HTTP中獲取請求參數(shù), 然后封裝到Param對象中.


          public?final class?RequestHelper {

          ????/**
          ?????* 獲取請求參數(shù)
          ?????*/

          ????public?static?Param createParam(HttpServletRequest request) throws IOException {
          ????????Map<String, Object> paramMap = new?HashMap<>();
          ????????Enumeration<String> paramNames = request.getParameterNames();
          ????????//沒有參數(shù)
          ????????if?(!paramNames.hasMoreElements()) {
          ????????????return?null;
          ????????}

          ????????//get和post參數(shù)都能獲取到
          ????????while?(paramNames.hasMoreElements()) {
          ????????????String?fieldName = paramNames.nextElement();
          ????????????String?fieldValue = request.getParameter(fieldName);
          ????????????paramMap.put(fieldName, fieldValue);
          ????????}

          ????????return?new?Param(paramMap);
          ????}
          }


          (5) HelperLoader 類


          到目前為止, 我們創(chuàng)建了ClassHelper, BeanHelper, IocHelper, ControllerHelper這四個Helper類, 我們需要一個入口程序來加載他們(實際上是加載靜態(tài)代碼塊), 當(dāng)然就算沒有這個入口程序, 這些類也會被加載, 我們這里只是為了讓加載更加集中.


          public?final?class?HelperLoader?{

          ????public?static?void?init()?{
          ????????Class[] classList = {
          ????????????ClassHelper.class,
          ????????????BeanHelper.class,
          ????????????IocHelper.class,
          ????????????ControllerHelper.class
          ????????};
          ????????for?(Class cls : classList) {
          ????????????ClassUtil.loadClass(cls.getName());
          ????????}
          ????}
          }


          (6) 實現(xiàn)前端控制器


          前端控制器實際上是一個Servlet, 這里配置的是攔截所有請求, 在服務(wù)器啟動時實例化.

          當(dāng)DispatcherServlet實例化時, 首先執(zhí)行 init() 方法, 這時會調(diào)用 HelperLoader.init() 方法來加載相關(guān)的helper類, 并注冊處理相應(yīng)資源的Servlet.


          對于每一次客戶端請求都會執(zhí)行 service() 方法, 這時會首先將請求方法和請求路徑封裝為Request對象, 然后從映射處理器 (REQUEST_MAP) 中獲取到處理器. 然后從客戶端請求中獲取到Param參數(shù)對象, 執(zhí)行處理器方法. 最后判斷處理器方法的返回值, 若為view類型, 則跳轉(zhuǎn)到j(luò)sp頁面, 若為data類型, 則返回json數(shù)據(jù).


          @WebServlet(urlPatterns = "/*", loadOnStartup = 0)
          public?class?DispatcherServlet extends?HttpServlet {

          ????@Override
          ????public?void?init(ServletConfig servletConfig) throws ServletException {
          ????????//初始化相關(guān)的helper類
          ????????HelperLoader.init();

          ????????//獲取ServletContext對象, 用于注冊Servlet
          ????????ServletContext servletContext = servletConfig.getServletContext();

          ????????//注冊處理jsp和靜態(tài)資源的servlet
          ????????registerServlet(servletContext);
          ????}

          ????/**
          ?????* DefaultServlet和JspServlet都是由Web容器創(chuàng)建
          ?????* org.apache.catalina.servlets.DefaultServlet
          ?????* org.apache.jasper.servlet.JspServlet
          ?????*/

          ????private?void?registerServlet(ServletContext servletContext) {
          ????????//動態(tài)注冊處理JSP的Servlet
          ????????ServletRegistration jspServlet = servletContext.getServletRegistration("jsp");
          ????????jspServlet.addMapping(ConfigHelper.getAppJspPath() + "*");

          ????????//動態(tài)注冊處理靜態(tài)資源的默認Servlet
          ????????ServletRegistration defaultServlet = servletContext.getServletRegistration("default");
          ????????defaultServlet.addMapping("/favicon.ico"); //網(wǎng)站頭像
          ????????defaultServlet.addMapping(ConfigHelper.getAppAssetPath() + "*");
          ????}

          ????@Override
          ????public?void?service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          ????????String?requestMethod = request.getMethod().toUpperCase();
          ????????String?requestPath = request.getPathInfo();

          ????????//這里根據(jù)Tomcat的配置路徑有兩種情況, 一種是 "/userList", 另一種是 "/context地址/userList".
          ????????String[] splits = requestPath.split("/");
          ????????if?(splits.length > 2) {
          ????????????requestPath = "/"?+ splits[2];
          ????????}

          ????????//根據(jù)請求獲取處理器(這里類似于SpringMVC中的映射處理器)
          ????????Handler handler = ControllerHelper.getHandler(requestMethod, requestPath);
          ????????if?(handler != null) {
          ????????????Class controllerClass = handler.getControllerClass();
          ????????????Object?controllerBean = BeanHelper.getBean(controllerClass);

          ????????????//初始化參數(shù)
          ????????????Param param = RequestHelper.createParam(request);

          ????????????//調(diào)用與請求對應(yīng)的方法(這里類似于SpringMVC中的處理器適配器)
          ????????????Object?result;
          ????????????Method actionMethod = handler.getControllerMethod();
          ????????????if?(param == null?|| param.isEmpty()) {
          ????????????????result = ReflectionUtil.invokeMethod(controllerBean, actionMethod);
          ????????????} else?{
          ????????????????result = ReflectionUtil.invokeMethod(controllerBean, actionMethod, param);
          ????????????}

          ????????????//跳轉(zhuǎn)頁面或返回json數(shù)據(jù)(這里類似于SpringMVC中的視圖解析器)
          ????????????if?(result instanceof?View) {
          ????????????????handleViewResult((View) result, request, response);
          ????????????} else?if?(result instanceof?Data) {
          ????????????????handleDataResult((Data) result, response);
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 跳轉(zhuǎn)頁面
          ?????*/

          ????private?void?handleViewResult(View view, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
          ????????String?path = view.getPath();
          ????????if?(StringUtils.isNotEmpty(path)) {
          ????????????if?(path.startsWith("/")) { //重定向
          ????????????????response.sendRedirect(request.getContextPath() + path);
          ????????????} else?{ //請求轉(zhuǎn)發(fā)
          ????????????????Map<String, Object> model = view.getModel();
          ????????????????for?(Map.Entry<String, Object> entry : model.entrySet()) {
          ????????????????????request.setAttribute(entry.getKey(), entry.getValue());
          ????????????????}
          ????????????????request.getRequestDispatcher(ConfigHelper.getAppJspPath() + path).forward(request, response);
          ????????????}
          ????????}
          ????}

          ????/**
          ?????* 返回JSON數(shù)據(jù)
          ?????*/

          ????private?void?handleDataResult(Data data, HttpServletResponse response) throws IOException {
          ????????Object?model = data.getModel();
          ????????if?(model != null) {
          ????????????response.setContentType("application/json");
          ????????????response.setCharacterEncoding("UTF-8");
          ????????????PrintWriter writer = response.getWriter();
          ????????????String?json = JSON.toJSON(model).toString();
          ????????????writer.write(json);
          ????????????writer.flush();
          ????????????writer.close();
          ????????}
          ????}
          }


          handwritten-mvc-framwork 實例


          到這里為止, handwritten-mvc-framwork ?框架已經(jīng)實現(xiàn)了Bean容器, IOC功能, MVC功能, 所以現(xiàn)在我們完全可以用 handwritten-mvc-framwork ?框架來寫一個實例了.


          (1) 業(yè)務(wù)類


          public?interface?IUserService?{
          ????List getAllUser();
          }

          @Service
          public?class?UserService?implements?IUserService?{
          ????/**
          ?????* 獲取所有用戶
          ?????*/

          ????public?List getAllUser() {
          ????????List userList = new?ArrayList<>();
          ????????userList.add(new?User(1, "Tom", 22));
          ????????userList.add(new?User(2, "Alic", 12));
          ????????userList.add(new?User(3, "Bob", 32));
          ????????return?userList;
          ????}
          }


          (2) 處理器


          @Controller
          public?class?UserController?{
          ????@Autowired
          ????private?IUserService userService;

          ????/**
          ?????* 用戶列表
          ?????* @return
          ?????*/

          ????@RequestMapping(value = "/userList", method = RequestMethod.GET)
          ????public?View getUserList()?{
          ????????List userList = userService.getAllUser();
          ????????return?new?View("index.jsp").addModel("userList", userList);
          ????}
          }


          (3) JSP頁面


          <%@?page?pageEncoding="UTF-8"?%>
          <%@?taglib?prefix="c"?uri="http://java.sun.com/jsp/jstl/core"?%>
          <c:set?var="BASE"?value="${pageContext.request.contextPath}"/>
          <html>
          <head>
          ????<title>用戶信息title>
          head>
          <body>
          <h1>用戶信息h1>
          <table>
          ????<tr>
          ????????<th>用戶idth>
          ????????<th>名稱th>
          ????????<th>年齡th>
          ????tr>
          ????<c:forEach?var="userinfo"?items="${userList}">
          ????????<tr>
          ????????????<td>${userinfo.id}td>
          ????????????<td>${userinfo.name}td>
          ????????????<td>${userinfo.age}td>
          ????????????<td>
          ????????????????<a?href="#">詳情a>
          ????????????????<a?href="#">編輯a>
          ????????????td>
          ????????tr>
          ????c:forEach>
          table>
          body>
          html>


          (4) 結(jié)果


          http://localhost:8081/handwritten/userList




          原文鏈接:blog.csdn.net/litianxiang_kaola/article/details/86647040



          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  草逼网页 | 久久久久久久久久97 | 无码无卡| 欧美久久国产精品 | 成人做爰A片免费看网站找不到了 |