正能量網(wǎng)站ip網(wǎng)絡(luò)營銷推廣有哪些方法
一、什么是MVC
MVC(Model-View-Controller)是一種軟件設(shè)計模式,用于組織和管理應(yīng)用程序的代碼結(jié)構(gòu)。它將應(yīng)用程序分為三個主要部分,即模型(Model)、視圖(View)和控制器(Controller),每個部分都有特定的職責和功能。
以下是 MVC 模式中各個組成部分的概述:
- 模型(Model):模型代表應(yīng)用程序的數(shù)據(jù)和業(yè)務(wù)邏輯。它負責處理數(shù)據(jù)的讀取、存儲、驗證和處理,以及執(zhí)行應(yīng)用程序的核心業(yè)務(wù)邏輯。模型通常是獨立于用戶界面的,可以被多個視圖和控制器共享。
- 視圖(View):視圖是用戶界面的表示,負責展示數(shù)據(jù)給用戶,并接收用戶的輸入。它通常是模型的可視化表現(xiàn)形式,負責將模型的數(shù)據(jù)呈現(xiàn)給用戶,并根據(jù)用戶的操作更新界面。視圖不處理業(yè)務(wù)邏輯,只負責顯示和接收用戶的操作。
- 控制器(Controller):控制器是模型和視圖之間的協(xié)調(diào)者,負責處理用戶的輸入、更新模型的數(shù)據(jù)以及更新視圖的顯示。它接收用戶的操作請求,調(diào)用相應(yīng)的模型方法進行數(shù)據(jù)處理和更新,并在必要時更新視圖以反映最新的數(shù)據(jù)。
MVC 的核心思想是將應(yīng)用程序的邏輯和數(shù)據(jù)分離,使其更易于理解、擴展和維護。通過將應(yīng)用程序的不同部分分離,MVC 模式提供了更好的代碼組織和可重用性。在 MVC 中,用戶與視圖進行交互,視圖通過控制器將用戶的操作轉(zhuǎn)發(fā)給模型進行處理,模型根據(jù)業(yè)務(wù)邏輯進行數(shù)據(jù)處理,然后通知視圖進行更新。這種分離和協(xié)作的方式使得應(yīng)用程序的不同部分能夠獨立地開發(fā)和測試,同時也提高了代碼的可維護性和重用性。
舉例來說,當瀏覽器發(fā)送一個查詢請求,要求查詢用戶信息時,Controller通過jdbc調(diào)用數(shù)據(jù)庫方法獲得對應(yīng)的User對象,然后將user對象傳遞給user.jsp渲染,并發(fā)送回瀏覽器。
二、Servlet
Servlet 是 Java 編程語言中的一種特殊類,用于處理 Web 應(yīng)用程序中的動態(tài)內(nèi)容和 HTTP 請求。Servlet 提供了一種基于服務(wù)器的編程模型,允許開發(fā)者通過編寫 Java 代碼來處理客戶端的請求并生成相應(yīng)的響應(yīng)。
實際上Servlet就是一個API接口,它需要底層的Web服務(wù)器實現(xiàn)HTTP協(xié)議的解析處理,但也以此將底層解析代碼對開發(fā)者屏蔽。使用者只需要關(guān)注上層的api接口的調(diào)用即可。我們使用Servlet API編寫自己的Servlet來處理HTTP請求,Web服務(wù)器實現(xiàn)Servlet API接口,實現(xiàn)底層功能。
用法關(guān)鍵在于繼承HttpServlet
,覆寫doPost, doGet等方法,并調(diào)用業(yè)務(wù)方法,返回HttpResponse。
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;// WebServlet注解表示這是一個Servlet,并映射到地址/:
@WebServlet(urlPatterns = "/")
public class UserServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {String action = request.getParameter("action");if (action != null) {switch (action) {case "register":handleRegistration(request, response);break;case "login":handleLogin(request, response);break;default:response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid action");}} else {response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Action parameter is missing");}}private void handleRegistration(HttpServletRequest request, HttpServletResponse response) throws IOException {// 處理用戶注冊邏輯// 從 request 中獲取用戶提交的注冊信息String username = request.getParameter("username");String password = request.getParameter("password");// 執(zhí)行用戶注冊操作,例如將用戶信息存儲到數(shù)據(jù)庫中// 返回注冊成功的響應(yīng)response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<html><body>");out.println("<h2>Registration successful</h2>");out.println("<p>Welcome, " + username + "!</p>");out.println("</body></html>");}private void handleLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {// 處理用戶登錄邏輯// 從 request 中獲取用戶提交的登錄信息String username = request.getParameter("username");String password = request.getParameter("password");// 執(zhí)行用戶登錄驗證操作,例如從數(shù)據(jù)庫中檢查用戶名和密碼是否匹配// 返回登錄成功或失敗的響應(yīng)response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("<html><body>");if (username.equals("admin") && password.equals("password")) {out.println("<h2>Login successful</h2>");out.println("<p>Welcome back, " + username + "!</p>");} else {out.println("<h2>Login failed</h2>");out.println("<p>Invalid username or password.</p>");}out.println("</body></html>");}
}
UserServlet 類繼承了 HttpServlet 并重寫了 doPost 方法來處理客戶端的 POST 請求。根據(jù)請求中的 action 參數(shù)的不同值,分別調(diào)用 handleRegistration 和 handleLogin 方法來處理用戶注冊和登錄邏輯。
要將Servlet部署到支持Servlet api的web服務(wù)器(Servlet容器如 Apache Tomcat),你需要將編譯后的類文件(例如 UserServlet.class)放置在正確的目錄結(jié)構(gòu)中,并在 web.xml 文件(位于 WEB-INF 目錄下)中進行配置。
具體配置參考 lxf Servlet教程
三、MVC框架原理和實現(xiàn)
參考lxf mvc高級開發(fā)
在使用Servlet的案例中,我們可以注意到,一個Servlet只能處理一個url下的Get Post請求,例如如果一個 Servlet 映射到路徑 /users,它將處理所有以 /users 開頭的請求路徑。
如果有一個MVC框架,能夠通過一個底層的DispatchServlet
,存儲所有的url到方法的映射,那就不需要重復繼承和編寫Servlet相關(guān)代碼,上層被映射的方法可以組織成一個純粹的Java類,只需要關(guān)注control部分的業(yè)務(wù)邏輯即可
public class UserController {@GetMapping("/signin")public ModelAndView signin() {...}@PostMapping("/signin")public ModelAndView doSignin(SignInBean bean) {...}@GetMapping("/signout")public ModelAndView signout(HttpSession session) {...}
}
以以上代碼為例,如果Servlet可以直接將doGet中與業(yè)務(wù)邏輯無關(guān)的內(nèi)容實現(xiàn),把Controller業(yè)務(wù)邏輯需要的功能抽象為新的類,返回值再通過ModelAndView傳送給Servlet,由Servlet交給底層渲染引擎得到View,就可以使代碼更加簡潔,擴展性更強。
MVC框架原理:
我們需要在MVC框架中創(chuàng)建一個接收所有請求的Servlet,通常我們把它命名為DispatcherServlet,它總是映射到/,然后,根據(jù)不同的Controller的方法定義的@Get或@Post的Path決定調(diào)用哪個方法,最后,獲得方法返回的ModelAndView后,渲染模板,寫入HttpServletResponse,即完成了整個MVC的處理。
結(jié)構(gòu)如下
DispatchServlet編寫
@WebServlet(urlPatterns = "/")
public class DispatcherServlet extends HttpServlet {private Map<String, GetDispatcher> getMappings = new HashMap<>(); //需要存儲請求路徑到某個具體方法的映射private Map<String, PostDispatcher> postMappings = new HashMap<>();
}//處理一個GET請求是通過GetDispatcher對象完成的,它需要如下信息
class GetDispatcher {Object instance; // Controller實例Method method; // Controller方法String[] parameterNames; // 方法參數(shù)名稱Class<?>[] parameterClasses; // 方法參數(shù)類型
}
使用invoke處理真正的請求
class GetDispatcher {...public ModelAndView invoke(HttpServletRequest request, HttpServletResponse response) {Object[] arguments = new Object[parameterClasses.length];for (int i = 0; i < parameterClasses.length; i++) {String parameterName = parameterNames[i];Class<?> parameterClass = parameterClasses[i];if (parameterClass == HttpServletRequest.class) {arguments[i] = request;} else if (parameterClass == HttpServletResponse.class) {arguments[i] = response;} else if (parameterClass == HttpSession.class) {arguments[i] = request.getSession();} else if (parameterClass == int.class) {arguments[i] = Integer.valueOf(getOrDefault(request, parameterName, "0"));} else if (parameterClass == long.class) {arguments[i] = Long.valueOf(getOrDefault(request, parameterName, "0"));} else if (parameterClass == boolean.class) {arguments[i] = Boolean.valueOf(getOrDefault(request, parameterName, "false"));} else if (parameterClass == String.class) {arguments[i] = getOrDefault(request, parameterName, "");} else {throw new RuntimeException("Missing handler for type: " + parameterClass);}}return (ModelAndView) this.method.invoke(this.instance, arguments);}private String getOrDefault(HttpServletRequest request, String name, String defaultValue) {String s = request.getParameter(name);return s == null ? defaultValue : s;}
}
Dispatch核心流程
public class DispatcherServlet extends HttpServlet {...@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html");resp.setCharacterEncoding("UTF-8");String path = req.getRequestURI().substring(req.getContextPath().length());// 根據(jù)路徑查找GetDispatcher:GetDispatcher dispatcher = this.getMappings.get(path);if (dispatcher == null) {// 未找到返回404:resp.sendError(404);return;}// 調(diào)用Controller方法獲得返回值:ModelAndView mv = dispatcher.invoke(req, resp);// 允許返回null:if (mv == null) {return;}// 允許返回`redirect:`開頭的view表示重定向:if (mv.view.startsWith("redirect:")) {resp.sendRedirect(mv.view.substring(9));return;}// 將模板引擎渲染的內(nèi)容寫入響應(yīng):PrintWriter pw = resp.getWriter();this.viewEngine.render(mv, pw);pw.flush();}
}
這樣使得上層代碼編寫更靈活。例如,一個顯示用戶資料的請求可以這樣寫
@GetMapping("/user/profile")
public ModelAndView profile(HttpServletResponse response, HttpSession session) {User user = (User) session.getAttribute("user");if (user == null) {// 未登錄,跳轉(zhuǎn)到登錄頁:return new ModelAndView("redirect:/signin");}if (!user.isManager()) {// 權(quán)限不夠,返回403:response.sendError(403);return null;}return new ModelAndView("/profile.html", Map.of("user", user));
}
最后一步是在DispatcherServlet的init()方法中初始化所有Get和Post的映射,以及用于渲染的模板引擎:
public class DispatcherServlet extends HttpServlet {private Map<String, GetDispatcher> getMappings = new HashMap<>();private Map<String, PostDispatcher> postMappings = new HashMap<>();private ViewEngine viewEngine;@Overridepublic void init() throws ServletException {this.getMappings = scanGetInControllers();this.postMappings = scanPostInControllers();this.viewEngine = new ViewEngine(getServletContext());}...
}
如何掃描所有Controller以獲取所有標記有@GetMapping和@PostMapping的方法,使用反射.