当前位置: 首页 > news >正文

Spring学习(三):MVC

一、什么是MVC

MVC(Model-View-Controller)是一种软件设计模式,用于组织和管理应用程序的代码结构。它将应用程序分为三个主要部分,即模型(Model)、视图(View)和控制器(Controller),每个部分都有特定的职责和功能。

以下是 MVC 模式中各个组成部分的概述:

  • 模型(Model):模型代表应用程序的数据和业务逻辑。它负责处理数据的读取、存储、验证和处理,以及执行应用程序的核心业务逻辑。模型通常是独立于用户界面的,可以被多个视图和控制器共享。
  • 视图(View):视图是用户界面的表示,负责展示数据给用户,并接收用户的输入。它通常是模型的可视化表现形式,负责将模型的数据呈现给用户,并根据用户的操作更新界面。视图不处理业务逻辑,只负责显示和接收用户的操作。
  • 控制器(Controller):控制器是模型和视图之间的协调者,负责处理用户的输入、更新模型的数据以及更新视图的显示。它接收用户的操作请求,调用相应的模型方法进行数据处理和更新,并在必要时更新视图以反映最新的数据。

MVC 的核心思想是将应用程序的逻辑和数据分离,使其更易于理解、扩展和维护。通过将应用程序的不同部分分离,MVC 模式提供了更好的代码组织和可重用性。在 MVC 中,用户与视图进行交互,视图通过控制器将用户的操作转发给模型进行处理,模型根据业务逻辑进行数据处理,然后通知视图进行更新。这种分离和协作的方式使得应用程序的不同部分能够独立地开发和测试,同时也提高了代码的可维护性和重用性。

在这里插入图片描述
举例来说,当浏览器发送一个查询请求,要求查询用户信息时,Controller通过jdbc调用数据库方法获得对应的User对象,然后将user对象传递给user.jsp渲染,并发送回浏览器。


二、Servlet

Servlet 是 Java 编程语言中的一种特殊类,用于处理 Web 应用程序中的动态内容和 HTTP 请求。Servlet 提供了一种基于服务器的编程模型,允许开发者通过编写 Java 代码来处理客户端的请求并生成相应的响应。

实际上Servlet就是一个API接口,它需要底层的Web服务器实现HTTP协议的解析处理,但也以此将底层解析代码对开发者屏蔽。使用者只需要关注上层的api接口的调用即可。我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,实现底层功能。

用法关键在于继承HttpServlet,覆写doPost, doGet等方法,并调用业务方法,返回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");// 执行用户注册操作,例如将用户信息存储到数据库中// 返回注册成功的响应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");// 执行用户登录验证操作,例如从数据库中检查用户名和密码是否匹配// 返回登录成功或失败的响应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 请求。根据请求中的 action 参数的不同值,分别调用 handleRegistration 和 handleLogin 方法来处理用户注册和登录逻辑。

要将Servlet部署到支持Servlet api的web服务器(Servlet容器如 Apache Tomcat),你需要将编译后的类文件(例如 UserServlet.class)放置在正确的目录结构中,并在 web.xml 文件(位于 WEB-INF 目录下)中进行配置。

具体配置参考 lxf Servlet教程


三、MVC框架原理和实现

参考lxf mvc高级开发
在使用Servlet的案例中,我们可以注意到,一个Servlet只能处理一个url下的Get Post请求,例如如果一个 Servlet 映射到路径 /users,它将处理所有以 /users 开头的请求路径。

如果有一个MVC框架,能够通过一个底层的DispatchServlet,存储所有的url到方法的映射,那就不需要重复继承和编写Servlet相关代码,上层被映射的方法可以组织成一个纯粹的Java类,只需要关注control部分的业务逻辑即可

public class UserController {@GetMapping("/signin")public ModelAndView signin() {...}@PostMapping("/signin")public ModelAndView doSignin(SignInBean bean) {...}@GetMapping("/signout")public ModelAndView signout(HttpSession session) {...}
}

以以上代码为例,如果Servlet可以直接将doGet中与业务逻辑无关的内容实现,把Controller业务逻辑需要的功能抽象为新的类,返回值再通过ModelAndView传送给Servlet,由Servlet交给底层渲染引擎得到View,就可以使代码更加简洁,扩展性更强。

MVC框架原理:

我们需要在MVC框架中创建一个接收所有请求的Servlet,通常我们把它命名为DispatcherServlet,它总是映射到/,然后,根据不同的Controller的方法定义的@Get或@Post的Path决定调用哪个方法,最后,获得方法返回的ModelAndView后,渲染模板,写入HttpServletResponse,即完成了整个MVC的处理。

结构如下
在这里插入图片描述
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; // 方法参数名称Class<?>[] parameterClasses; // 方法参数类型
}

使用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());// 根据路径查找GetDispatcher:GetDispatcher dispatcher = this.getMappings.get(path);if (dispatcher == null) {// 未找到返回404:resp.sendError(404);return;}// 调用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;}// 将模板引擎渲染的内容写入响应: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) {// 未登录,跳转到登录页:return new ModelAndView("redirect:/signin");}if (!user.isManager()) {// 权限不够,返回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的方法,使用反射.

相关文章:

Spring学习(三):MVC

一、什么是MVC MVC&#xff08;Model-View-Controller&#xff09;是一种软件设计模式&#xff0c;用于组织和管理应用程序的代码结构。它将应用程序分为三个主要部分&#xff0c;即模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;…...

排查disabled问题之谷歌新版本特性

问题复现 最近我突然接手一个后台的bug&#xff0c;这个后台很久没有迭代更新了&#xff0c;我也不熟悉业务&#xff0c;所以只能看一下源码&#xff0c;问题很快就复现&#xff0c;测试的修复操作也很正确&#xff0c;就是因为渲染的input标签中存在disableddisabled’属性导…...

三、开发工具

开发工具 开发工具1.1.熟悉IDEA1.2.下载IDEA1.3.IDEA中文插件1.4.IDEA输出中文乱码1.5.使用IDEA —————————————————————————————————————————————————— —————————————————————————————————…...

代码解读:y.view(y.size(0), -1)---tensor张量第一维保持不变,其余维度展平

y.view(y.size(0), -1)代码解读&#xff1a; 用于改变PyTorch张量&#xff08;tensor&#xff09;y的形状的。 y.size(0)返回y的第一维的大小。 -1表示让PyTorch自动计算该维度的大小&#xff0c;以确保新的张量与原始张量有相同的元素数量。 功能&#xff1a;将y的第一维保持…...

必示科技赋能广发证券运维数字化实践案例,入选信通院《中国AIOps现状调查报告(2023)》

近期&#xff0c;“必示科技赋能广发证券运维数字化实践&#xff0c;打造智能运维数据中台”合作案例被中国信息通信研究院作为优秀金融案例项目&#xff0c;收录在最新的《中国AIOps现状调查报告&#xff08;2023&#xff09;》&#xff08;金融行业仅3家&#xff09;。 以必…...

特斯拉Dojo超算:AI训练平台的自动驾驶与通用人工智能之关键

特斯拉公开Dojo超算架构细节&#xff0c;AI训练算力平台成为其自动驾驶与通用人工智能布局的关键一环 在近日举行的Hot Chips 34会议上&#xff0c;特斯拉披露了其自主研发的AI超算Dojo的详细信息。Dojo是一个可定制的超级计算机&#xff0c;从芯片到系统全部由特斯拉自主设计…...

Linux中的一些常用命令

1.查看Linux系统中自带的GLIBC版本 ldd --version2.Linux中删除文件的命令 在Linux中&#xff0c;删除文件的命令是 rm。 使用 rm 命令时&#xff0c;请小心使用&#xff0c;因为它将直接删除文件&#xff0c;而不会将其移动到回收站。 以下是 rm 命令的一些常用选项&#…...

VRTK4⭐二.VRTK4的项目基础配置

文章目录 &#x1f7e5; 硬件基本配置&#x1f7e7; 设置XR Plug-in Management&#x1f7e8; 添加项目Tilia&#x1f7e9; 配置项目Hierarchy &#x1f7e5; 硬件基本配置 解决使用OpenXR,HTC头显正常追踪,但手柄无法使用的问题. 问题如下: 当我们按照官方的标准流程配置完Op…...

word-doc和docx区别

office从业者路过。 文件结构上doc文件数据是以二进制形式存放的。 docx是以xml文件形式存放的。 doc兼容较差&#xff0c;docx效果更好。...

深度学习-偏导数复习

文章目录 前言1.偏导数2.偏导数概念1.对x的偏导数2.对y的偏导数3.多元函数偏导数4.如何计算偏导数1.二元函数的偏导数2.复杂函数的偏导数3.分段函数1.分界点的偏导数 5.偏导数与连续之间的关系6.偏导数的几何意义7.高阶偏导数1.定义2.高阶偏导数例题&#xff08;二阶偏导数&…...

linux之jq命令

jq命令用于linux命令行对json进行处理 参数 option -r&#xff1a;去掉字符串的引号"例子 tt.json文件如下&#xff1a; [{"metric": "httpcode","tags": {"cluster": "tt","domain": "www.baidu.…...

nginx知识点详解:反向代理+负载均衡+动静分离+高可用集群

一、nginx基本概念 1. nginx是什么&#xff0c;做什么事情&#xff1f; Nginx是一个高性能的HTTP和反向代理服务器&#xff0c;特点是占有内存少&#xff0c;并发能力强。Nginx转为性能优化而开发&#xff0c;能经受高负载考验。支持热部署&#xff0c;启动容易&#xff0c;运…...

powerDesigner 的基本使用

打开powerDesigner 新建 PDM(物理数据模型) 添加表字段 双击表&#xff0c;设置ID自增 选择导出数据库表SQL 导出成功 使用三方工具连接数据库&#xff0c;然后运行对应SQL文件即可 导入SQL文件数据到powerDesigner...

Java下打印一个等腰三角型

想达到这个结果&#xff0c;通常的做法是通过拼结两个三角型达到&#xff0c;但是实际上还有最右边的第三个三角型没有处理&#xff0c;这个拼结的方法总让人看起来有一点不完美的感觉&#xff0c;于是我自创了一个思路&#xff0c;一气合成&#xff0c;代码如下&#xff08;本…...

HR的职业规划

CHRO可以说是HR职业发展的天花板了。CHRO对一个企业来说至关重要&#xff0c;是CEO的左膀右臂。那从CEO的角度来看CHRO&#xff0c;应该具备什么样的素质和能力&#xff0c;又能为公司带来什么样的价值呢&#xff1f; 在公司的不同发展阶段&#xff0c;HR部门有着不同的战略和…...

avi怎么转换成视频?

avi怎么转换成视频&#xff1f;在我们日常使用的视频格式中&#xff0c;AVI是一种常见且经常被使用的音频视频交叉格式之一。它的优点之一是占用的存储空间相对较小&#xff0c;但也明显存在着画质损失的缺点。虽然AVI格式的视频在某种程度上也很常见&#xff0c;但与最常见的M…...

爬虫数据存储:技术、策略与实践(一)

文章目录 &#x1f34b;引言&#x1f34b;xlrd库和xlwt库&#x1f34b;创建Excel文件&#x1f34b;通过Python代码向Excel写入数据&#x1f34b;案例实战 &#x1f34b;引言 本节主要介绍一下在使用网络爬虫技术的时候&#xff0c;如何将数据存储到Excel中去 &#x1f34b;xl…...

【音视频】ffplay解析-音视频同步

音视频同步 主要解析&#xff1a;以音频为基准&#xff0c;让视频合成音频 思路 视频慢了则丢掉部分视频帧&#xff08;视觉->画⾯跳帧&#xff09; 视频快了则继续渲染上⼀帧 具体实现 一个国际标准&#xff1a;音频帧-视频帧时间戳的差值在-100ms~25ms内流畅 1.差值音频…...

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表

虚拟列表 - Vue3实现一个可动态改变高度的虚拟滚动列表 前言 在开发中经常遇到大量的渲染列表数据问题&#xff0c;往往我们就只是简单地遍历渲染&#xff0c;没有过多地去关注是否会存在性能问题&#xff0c;这导致如果数据量较大的时候&#xff0c;比如上万条数据&#xff…...

PyTorch实战:实现Cifar10彩色图片分类

目录 前言 一、Cifar10数据集 class torch.utils.data.Dataset torch.utils.data.DataLoader 二、定义神经网络 普通神经网络: 定义损失函数和优化器 训练网络-Net CPU训练 模型准确率 ​编辑 GPU训练 训练网络-LeNet 模型准确率 点关注&#xff0c;防走丢&#x…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...