Spring MVC程序开发

目录

1. 什么是Spring MVC?

1.1 什么是MVC

1.2 MVC和Spring MVC 的关系

1.3 为什么要学Spring MVC?

2. Spring MVC的使用

2.1 Spring MVC的创建和连接

2.1.1 项目创建

2.1.2 项目连接

2.1.2.1 连接

2.1.2.2 @RequestMapping注解介绍

2.1.2.3 @GetMapping和 @PostMapping

2.2 获取参数

获取单个参数

获取多个参数

获取对象

@RequestParam重命名后端参数 (后端参数映射)

设置参数必传@RequestParam

非必传参数设置

@RequestBody接收JSON对象

@PathVariable获取URL基础参数(不是从URL参数部分获取参数)

@RequestPart上传文件

@CookieValue获取Cookie

@RequestHeader获取header

@SessionAttribute获取Session

2.3 返回数据

返回静态页面

返回text/html

返回JSON对象

请求转发或请求重定向

两者区别

定义

请求方

数据共享

最终URL

代码实现不同

查看更多注解


1. 什么是Spring MVC?

官方描述:

Spring Web MVC is the original web framework built on the Servlet APl and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC", comes from the name of its source module (spring-webmvc), but it is more commonly known as "Spring MVC"
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称“Spring MVC”

由官方对Spring MVC的定义可以知道:

  1. Spring MVC是一个Web框架;
  2. Spring MVC是基于Servlet API构建的.

1.1 什么是MVC

定义: MVC是Model View Controller的缩写, 它是软件工程中的一种软件架构模式, 它把软件系统分为 模型, 视图, 控制器 三个基本部分.

  • Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
  • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
  • Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据控制用户输入,并向模型发送数据

当用户发送请求的时候, 请求会首先来到Controller控制器, 然后在Controller里面 验证完请求没有问题之后就会将请求转发给Model模型层(也就是数据模型), 然后数据模型会根据请求的信息得到相应的结果, 然后把结果返回给控制器, 接下来控制器再把结果交给View视图渲染器, 然后View就根据它的模板并加上返回来的数据进行数据的解析和渲染, 最终将用户可以看得懂的页面交给用户, 这样就完成了一次响应. 这是最初的MVC的机制.

模型层是比较广义上的模型层, 程序中实体类所在的层就是这个Model模型层, 也可以叫做entity, 那么这里的模型指的是数据模型.
但是目前来讲这种模式已经过时了, 现在都是在做前后端分离的, 已经不再使用View这种已经淘汰的技术来返回页面给用户.
Spring提供的Web容器只有这一个, 我们实现的是基于http协议的, 所以我们需要用这个框架.
Spring MVC经过它的演变和改善, 是可以直接从Controller返回数据给用户的, 也就是说不再经过View视图的渲染了.

1.2 MVC和Spring MVC 的关系

MVC 是一种思想,而 Spring MVC 是对 MVC 思想的具体实现。

总结来说,Spring MVC 是一个实现了 MVC 模式,并继承了 Servlet API的 Web 框架。既然是 Web框架,那么当用户在浏览器中输入了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求。

1.3 为什么要学Spring MVC?

现在绝大部分的 Java 项目都是基于 Spring (或 Spring Boot)的,而 Spring 的核心就是 Spring MVC。也就是说 Spring MVC 是 Spring 框架的核心模块,而 Spring Boot 是 Spring 的脚手架,因此我们可以推断出,现在市面上绝大部分的 Java 项目约等于 Spring MVC 项目,这是我们要学 SpringMVC 的原因。

2. Spring MVC的使用

学习Spring MVC的使用需要掌握以下它的功能:

  1. 连接的功能: 将用户 (浏览器) 和 Java 程序连接起来,也就是访问一个地址能够调用到我们Spring程序。
  2. 获取参数的功能: 用户访问的时候会带一些参数,在程序中能够获取到用户输入的参数。
  3. 输出数据的功能: 执行了业务处理,然后把程序执行的结果返回给用户。

2.1 Spring MVC的创建和连接

2.1.1 项目创建

Spring MVC 可以基于 Spring Boot 创建,也就是创建一个 Spring Boot 项目,勾选上 Spring Web模块即可,如下图所示:

2.1.2 项目连接

2.1.2.1 连接

接下来,创建一个 UserController 类,实现用户到 Spring 程序的互联互通, 具体实现代码如下:

package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;//@Controller     // 让 Spring 框架启动时, 加载
//@ResponseBody   // 返回非页面数据
@RestController     // = @Controller + @ResponseBody
public class UserController {@RequestMapping("/say")    // 该注解能让后端获取到用户请求, 后文介绍该注解public String sayHi(){return "Hi Spring MVC";}
}

这样实现之后,当访问地址: http://localhost:8080/say 时就能打印"Hi Spring MVC"的信息了.

2.1.2.2 @RequestMapping注解介绍

@RequestMapping 是 Spring Web 的常用注解之一,它是用来注册接口的路由映射的。

路由映射: 当用户访问一个 url 时, 将用户的请求对应到程序中某个的某个方法的过程就叫路由映射.

@RequestMapping的使用就如上面例子的打印"Hi Spring MVC"所示, 上例是用于修饰方法的, 那么它也可以用于修饰类. 当修饰了类和方法之后就要注意访问地址为: 类+方法.

注: 还可以在一个@RequestMapping中设置多级路由.

@RequestMapping能够支持较多的请求, 最常见的就是GET和POST, 那么它也能够支持PUT, PATCH, DELETE等其他请求, 适用范围较广. 我们通过工具Postman来发送不同种类的请求来验证(验证过程略). 也可以在它的源码中找到.

从源码中我们可以知道, 我们还可以通过加method来控制@RequestMapping的请求类型, 比如:

@RequestMapping(value = "/say", method = RequestMethod.POST)

此时只有POST类型的请求能够获取, 其他类型的请求就无法获取, 比如获取GET, 就会直接报错.

2.1.2.3 @GetMapping和 @PostMapping

通过@GetMapping和 @PostMapping可以单独的只支持GET请求或者POST请求.

@PostMapping("/sayhello")
public String sayHello() {return "hello spring mvc";
}@GetMapping("/hi")
public String hi() {return "spring mvc hi";
}

2.2 获取参数

获取单个参数

在Spring MVC中可以直接用方法中的参数来实现传参,比如以下代码:

@RequestMapping("/sayhi")
public String sayHi(String name) {return "Hi " + name;
}

获取多个参数

@RequestMapping("/sayhi") // 可以是一级路由, 也可以是 N 级路由
public String sayHi(String name, String password) {return "hi " + name + " | password: " + password;
}

注意: 当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果。

获取对象

package com.example.demo.entity;import lombok.Data;@Data
public class Userinfo {private int id;public String name;private String password;private int age;
}
@RequestMapping("/reg")
public Object reg(Userinfo userinfo) {System.out.println(userinfo);return userinfo;
}


@RequestParam重命名后端参数 (后端参数映射)

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个username 给后端,而后端又是有name字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用 @RequestParam 来重命名前后端的参数值。

@RequestMapping("/reg2")
public Object reg2(@RequestParam("username") String name, String password) {return name + " : " + password;
}

设置参数必传@RequestParam

上面的例子,如果我们是前端传递一个非 username 的参数,就会出现程序报错的情况,如下图所示:

这是因为后端已经声明了前端必须传递一个username的参数,但是前端没有给后端传递,我们查看@RequestParam 注解的实现细节就可以发现端倪,注解实现如下:

required: 必须的意思,默认值为 true,因此不传递此参数就会报 400 的错误.

非必传参数设置

如果我们的实际业务前端的参数是一个非必传的参数,我们可以通过设置 @RequestParam 中的required=false 来避免不传递时报错,具体实现如下:

@RequestMapping("/reg2")
public Object reg2(@RequestParam(value = "username", required = false) String name, String password) {return name + " : " + password;
}

@RequestBody接收JSON对象

@RequestMapping("/reg3")
public Object reg3(@RequestBody Userinfo userinfo) {return userinfo;
}

@PathVariable获取URL基础参数(不是从URL参数部分获取参数)

@RequestMapping("/reg4/{name}/{pwd}")
public Object reg4(@PathVariable String name, @PathVariable(required = false, name = "pwd") String password) {return "name=" + name + " | password=" + password;
}

注意事项: @PostMapping("/reg4/{name}/{password}")中的 {password} 参数不能省略

@RequestPart上传文件

    @RequestMapping("/myupload")public Object upload(@RequestPart("myimg6") MultipartFile file) {String fileName = UUID.randomUUID() +    // 文件名file.getOriginalFilename().substring(   // 文件后缀file.getOriginalFilename().lastIndexOf("."));File saveFile = new File("D:\\JavaWebStudy\\" + fileName);try {file.transferTo(saveFile);return true; } catch (IOException e) {e.printStackTrace();}return false;}

通过Postman模拟上传文件,

注: 文件大小有要求, 那么可以通过Spring官方文档查询默认值, 进而在配置文件中修改默认大小. Common Application Properties

@CookieValue获取Cookie

@RequestMapping("/getck")
public Object getCk(@CookieValue(value = "java", required = false) String java) {return java;
}

注意, 直接访问/getck是没有任何东西在页面上的, 那么需要我们F12中手动伪造一份Cookie, 才能看见.

@RequestHeader获取header

@RequestMapping("/gethd")
public Object getHeader(@RequestHeader("Host") String host) {return "header -> " + host;
}

@SessionAttribute获取Session

    private static final String SESSION_KEY = "USERINFO_SESSION_KEY";// 存储 session@RequestMapping("/setsess")public void setSess(HttpServletRequest request) {HttpSession session = request.getSession();session.setAttribute(SESSION_KEY, "zhangsan");}// 获取 session@RequestMapping("/getsess")public Object getSession(@SessionAttribute(SESSION_KEY) String name) {return "session -> " + name;}

执行完localhost:8080/setsess后再访问localhost:8080/getsess

2.3 返回数据

返回静态页面

在resources.static中创建前端页面index.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>index.html</title>
</head>
<body><h1>hello index</h1>
</body>
</html>

创建控制器TestController:

package com.example.demo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/test")
public class TestController {@RequestMapping("/index")public Object getIndex(){return "/index.html";}
}


注意代码中的返回路径:

当return中加了"/"之后就代表是从根路径去找index.html的.

当不加"/"的时候, 它是在"/test"底下去找index.html的, 即在当前目录底下去找index.html的. 显然在上面的URL并找不到, 因为index.html是放在根路径下的.



返回text/html

package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class OwnerController {@RequestMapping("/m7")public String method_1(){return "<h1>hi, h1.</h1>";}
}

返回JSON对象

    @RequestMapping("/m2")public HashMap<String, String> method_2(){HashMap<String, String> map = new HashMap<>();map.put("C", "C Value");map.put("Java", "Java Value");map.put("MySQL", "MySQL Value");return map;}

请求转发或请求重定向

    // TestController下, 类注解@RequestMapping("/test")// 请求转发@RequestMapping("/fw")public String fw(){return "forward:/index.html";}// 请求重定向@RequestMapping("/rd")public String rd(){return "redirect:/index.html";}

请求转发和请求重定向的直观区别:

请求转发: 当输入localhost:8080/test/fw后, URL不变.

请求重定向: 当输入localhost:8080/test/rd后, URL变为localhost:8080/index.html


两者区别

定义

请求转发(Forward)是发生于服务器程序内的, 当服务器收到客户端的请求之后, 服务器会先将请求转发给目标地址, 由目标地址对请求进行处理, 再将目标地址返回的结果返回给客户端. 那么显然客户端就只知道发出了请求, 并收到了返回结果, 但是客户端并不知道服务器内部发生了转发行为.

请求重定向(Redirect)主要发生于客户端程序内, 当服务器收到客户端的请求之后, 服务器会给客户端发送一个用于重定向的临时响应头, 这个响应头记录了重定向之后的目标地址, 然后客户端会向这个目标地址发起请求.

请求方


数据共享

请求转发是由服务器实现的, 在整个执行流程中, 客户端只会发送一次请求, 所以在整个交互过程中使用的都是同一个请求对象和响应对象, 这说明在请求和返回的数据是共享的.

请求重定向则是客户端向服务器发起两次完全不同的请求, 所以两次请求中的数据是不同的.

最终URL

请求转发是服务器端代为请求,再将结果返回给客户端的,所以整个请求的过程中 URL 地址是不变的;

而请求重定向是服务器端告诉客户端,"你去另一个地访问去”,所以浏览器会重新再发送一次请求,因此客户端最终显示的 URL也为最终跳转的地址,而非刚开始请求的地址,所以 URL 地址发生了改变.

代码实现不同

由前文例子可见.

注: 以上关于请求转发和请求重定向的区别说明摘自请求转发和请求重定向有什么区别? | Javaᶜⁿ 面试突击


查看更多注解

Request Mapping :: Spring Framework

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/61538.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

17.电话号码的字母组合(回溯)

目录 一、题目 二、代码 一、题目 17. 电话号码的字母组合 - 力扣&#xff08;LeetCode&#xff09; 二、代码 class Solution {const char*data[10]{"","","abc","def","ghi","jkl","mno","pq…

鸿蒙边缘计算网关正式开售

IDO-IPC3528鸿蒙边缘计算网关基于RK3568研发设计&#xff0c;采用22nm先进工艺制程&#xff0c;四核A55 CPU&#xff0c;主频高达2.0GHz&#xff0c;支持高达8GB高速LPDDR4&#xff0c;1T算力NPU&#xff0c;4K H.265/H264硬解码&#xff1b;视频输出接口HDMI2.0&#xff0c;双…

OpenMV 自适应颜色阈值

目录 演示视频 思路讲解 OprnMV代码 演示视频 备战2023电赛~openmv自适应颜色阈值&#xff08;附源代码网盘链接&#xff09; 思路讲解 1. 参考openmv官方例程讲解10-Color-Tracking->image_statistics_info图像统计信息https://book.openmv.cc/example/10-Color-Trackin…

https的原理和方案

文章目录 https原理为什么要加密常见的加密方式对称加密非对称加密数据摘要&&数据指纹数据签名 https的几种工作方案方案一&#xff1a;只使用对称加密方案二&#xff1a;只使用非对称加密方案三&#xff1a;两端都使用非对称加密方案四&#xff1a;非对称加密 对称加…

前端项目环境变量如何配置?

我们在项目开发过程中&#xff0c;至少会经历开发环境、测试环境和生产环境三个阶段。不同阶段请求的状态&#xff08;如接口地址等&#xff09;不尽相同&#xff0c;若手动切换接口地址是相当繁琐切容易出错的。于是环境变量配置的需求就应运而生&#xff0c;我们只需做简单的…

花费7元训练自己的GPT 2模型

在上一篇博客中&#xff0c;我介绍了用Tensorflow来重现GPT 1的模型和训练的过程。这次我打算用Pytorch来重现GPT 2的模型并从头进行训练。 GPT 2的模型相比GPT 1的改进并不多&#xff0c;主要在以下方面&#xff1a; 1. GPT 2把layer normalization放在每个decoder block的前…

【数理知识】最小二乘法,从线性回归出发,数值举例并用最小二乘法求解回归模型

序号内容1【数理知识】自由度 degree of freedom 及自由度的计算方法2【数理知识】刚体 rigid body 及刚体的运动3【数理知识】刚体基本运动&#xff0c;平动&#xff0c;转动4【数理知识】向量数乘&#xff0c;内积&#xff0c;外积&#xff0c;matlab代码实现5【数理知识】协…

160. 相交链表 题解

题目描述&#xff1a;160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 注&#xff1a;本题中链表相交是“Y”型的&am…

【学习日记】【FreeRTOS】调度器函数实现详解

写在前面 本文主要是对于 FreeRTOS 中调度器函数实现的详细解释&#xff0c;代码大部分参考了野火 FreeRTOS 教程配套源码&#xff0c;作了一小部分修改。 一、MSP 和 PSP Cortex-M有两种栈空间&#xff0c;主堆栈和进程堆栈。 MSP 用于系统级别和中断处理的堆栈 MSP 用于保…

Linux系统调试课:Linux Kernel Printk

🚀返回专栏总目录 文章目录 0、printk 说明1、printk 日志等级设置2、屏蔽等级日志控制机制3、printk打印常用方式4、printk打印格式0、printk 说明 在开发Linux device Driver或者跟踪调试内核行为的时候经常要通过Log API来trace整个过程,Kernel API printk()是整个Kern…

idea 加入 .so文件

背景 做项目的时候&#xff0c;遇到需要查看native 方法 涉及到c源码的查看&#xff0c;因此需要加载.so文件去查看。 操作 idea-file-project structure 找到lib&#xff0c;把你的.so文件添加进来就可以啦 然后你就可以查看对应的源码了。

利用ChatGPT绘制思维导图——以新能源汽车竞品分析报告为例

随着人们对环境保护的日益关注和传统燃油汽车的限制&#xff0c;全球范围内对新能源汽车的需求不断增长。新能源汽车市场的激烈竞争使得了解各个竞品的特点和优劣成为关键。然而&#xff0c;针对这一领域的详尽竞品分析却常常需要大量时间和精力。 在此背景下&#xff0c;人工智…