1、SpringMVC是什么
Spring MVC(Model-View-Controller)是Spring框架的一部分,是基于Servlet API构建的Web原始框架。用于开发基于Java的Web应用程序。它采用MVC设计模式,将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。
- SpringMVC 是一个Web框架。
- SpringMVC是基于Servlet API构建的。
1.1、MVC定义
- 模型(Model): 表示应用程序中的数据和业务逻辑。在Spring MVC中,通常使用POJO(Plain Old Java Object)作为模型对象。通常模型对象负责在数据库中存取数据。
- 视图(View): 负责展示用户界面,通常是HTML页面、JSON响应或其他类型的视觉呈现。视图负责将模型数据渲染,并向用户呈现。
- 控制器(Controller): 接收并处理HTTP请求,并根据请求的内容选择相应的处理方法。控制器负责调度适当的业务逻辑,操作模型数据,并通过相应的视图返回响应结果。
MVC模式遵循单一职责原则,将应用程序的不同方面分离开来,使得每个部分都可以独立进行修改和扩展,提高了代码的可维护性和可测试性。同时,它也带来了更好的代码组织和清晰的逻辑层次。
在MVC模式中,用户与视图进行交互,视图将用户的请求发送给控制器,控制器根据请求调用相应的模型进行数据处理和更新,并选择合适的视图进行展示。这种分离使得每个部分可以独立开发、测试和维护,同时也支持更好的可重用性和可扩展性。
总而言之,MVC模式通过将应用程序划分为模型、视图和控制器三个组件,实现了数据、展示和交互的分离,以提供灵活、可维护和可扩展的软件设计方案。
1.2、MVC和 SpringMVC的关系
Spring MVC是在MVC模式的基础上实现的一种Web框架,或者说是MVC是一种思想,而SpringMVC是一种具体实现。它利用了MVC的优势并添加了更多的功能和便利性,使得开发者可以更轻松地构建和维护现代化的Web应用程序。
2.创建SpringMVC项目
在创建SpringBoot项目时,我们勾选的SpringWeb框架就是SpringMVC框架,因此照着SpringBoot创建流程就可以,只需添加SpringWeb依赖。【SpringBoot创建 链接】
2.1、SpringMVC 链接
在SpringMVC项目中使用@RequestMapping
注解来实现URL路由映射。也就是在浏览器上连接程序的作用。接下来实现的访问地址localhost:8080/hi
打印“hello SpringMVC”信息。
- 创建UserController类,实现用户到Spring 程序的连接。
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@ResponseBody //返回非页面数据 (默认是返回静态页面的)
public class UserController {
@RequestMapping("/hi") //注册路由
public String sayHi(){
return "hello SpringMVC";
}
}
- 运行启动类,访问
localhost:8080/hi
2.2、@RequestMapping 注解说明
@RequestMapping是SpringWeb应用程序中最常被用到的注解之一,它是用来注册路由映射的。
路由映射:当用户访问一个url时,将用户的请求对应到程序中的某个类的某个方法的过程就叫做路由映射。
在使用@RequestMapping注解时,可以按照以下方式进行使用:
- 在控制器类的方法上使用@RequestMapping注解:
@RestController //@RestController = @ResponseBody + @Controller
public class MyController {
@RequestMapping("/hello")
public String hello() {
return "Hello, world!";
}
}
上述代码演示了一个简单的示例,当访问路径为localhost:8080/hello
时,将会执行hello()方法,并返回"Hello, world!"。@RequestMapp即可修饰类,也可同时修饰方法,当修饰类和方法时,访问的地址就是 “类的路由+方法的路由”。
- 在控制器类和方法上使用@RequestMapping注解:
@RestController
@RequestMapping("/user")
public class MyController {
@RequestMapping("/hello")
public String hello() {
return "Hello, world!";
}
}
上述代码演示了一个简单的示例,当访问路径为localhost:8080/user/hello
时,将会执行hello()方法,并返回"Hello, world!"。
- 指定请求的HTTP方法:GET/POST
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "Hello, world!";
}
可以通过method属性来指定具体的HTTP方法,例如GET、POST等。上述代码指定了只有当使用GET方法访问路径为"/hello"时,hello()方法才会被执行。【可以使用postman操作get请求】
- 接收路径参数:
import org.springframework.web.bind.annotation.PathVariable;
@RequestMapping("/hello/{name}")
public String hello(@PathVariable String name) {
return "Hello, " + name + "!";
}
可以通过使用@PathVariable注解来接收路径中的参数。上述代码中的{name}表示路径中的参数,该参数将会传递给hello()方法并被使用,访问http://localhost:8080/hello/zhangsan
,会把zhangsan传给name,并显示到页面。
- 支持多个路径映射:
@RequestMapping(value = {"/hello", "/greeting"})
public String hello() {
return "Hello, world!";
}
可以通过将多个路径作为数组或多个值传递给@RequestMapping注解的value属性,来支持多个路径映射,此时访问路径为localhost:8080/hello
或者localhost:8080/greeting
都可以访问到hello()方法。
2.3 、 @GetMapping 和 @PostMapping
@GetMapping和@PostMapping是Spring Framework中的注解,用于定义HTTP请求的处理方法的映射。
@GetMapping注解表示该方法用于处理HTTP GET请求。
@PostMapping注解表示该方法用于处理HTTP POST请求。
- @GetMapping注解 3种写法
//1.
@RequestMapping("/hello")
//2.
@RequestMapping(value = "/hello", method = RequestMethod.GET)
//3.
GetMapping("/hello")
- @PostMapping注解2种写法
// 写法1
@RequestMapping(value = "/hello",method = RequestMethod.POST)
// 写法2
@PostMapping("/hello")
3、获取参数
3.1、传递单个参数
在SpringMVC中可以直接用方法中的参数来实现传参:
@RequestMapping("/hello")
public String sayHi(String name){
return "hello SpringMVC" + name;
}
使用postman访问方法:
3.2、传递多个参数/表单参数传递
@RequestMapping("/prams")
public String prams(String name,Integer id) {
return "name : "+name+" ,id:" +id;
}
前端访问:
注意:当有多个参数时,前后端进行参数匹配时,是根据参数的名称进行匹配的,并不会因为参数的顺序和位置发生变化影响后端获取参数的结果。
3.3、传递对象
SpringMVC可以自动的实现对象参数的赋值,比如Person对象:
import lombok.Data;
@Data //自动生成setter和getter、toString方法
public class Person {
private int id;
private String name;
}
传递对象实现:
@RequestMapping("/person")
public String person(Person person) {
return person.getName()+ ":" + person.getId();
}
前端访问:
3.4、后端参数重命名(后端参数映射)
可以通过在@RequestParam
注解中指定value
或name
属性来实现前后端参数值重命名。
下面是使用@RequestParam
注解进行参数重命名的示例:
@GetMapping("/search")
public String search(@RequestParam(value = "q") String query) {
// ...
return "Search result for: " + query;
}
在上述示例中,通过value = "q"
将参数重命名为"q",并将其绑定到query
参数上。请求中传递的参数名称应为"q",而不是方法参数名。
另一种方式是使用name
属性,它与value
属性具有相同的效果:
@GetMapping("/search")
public String search(@RequestParam(name = "q") String query) {
// ...
return "Search result for: " + query;
}
使用postman访问:
- 注意:如果此时不传入参数就会报错
这是因为后端声明了前端必须传递一个“q”参数,但是前端没有给后端传递,于是就报错了,我们查看以下@RequestParam的注解实现细节就可以发现问题,注解实现如下:
在未明确指定required
属性时,默认值为true
,即传递参数为必需的。如果请求中没有传递该参数,服务器将返回400 Bad Request错误。
3.4.1、非必传参数设置
如果我们要实现前端参数是一个非必传参数,可以通过设置@RequestParam种的required=false来避免不传递参数而报错:
@GetMapping("/search")
public String search(@RequestParam(value = "q",required = false) String query) {
// ...
return "Search result for: " + query;
}
使用postman访问:
如果将required
属性设置为false
,则查询参数变为可选,不再强制要求请求中包含该参数。此时,如果请求中没有传递该查询参数,方法参数将被设置为null
,并且方法仍然能够正常调用。
3.5、接收JSON对象
还是person类
import lombok.Data;
@Data //自动生成setter、getter等方法
public class Person {
private int id;
private String name;
}
接收代码:
import org.springframework.web.bind.annotation.*;
@RequestMapping(value = "/person",method = RequestMethod.POST)
public Person person(@ResponseBody Person person) {
System.out.println(person.getId()+": "+person.getName());
return person;
}
使用postman访问:
使用@RequestBody
注解将请求体的JSON数据绑定到方法参数上。然后,将参数声明为一个合适的Java对象类型,Spring将根据请求体的JSON数据自动进行反序列化,并将其转换为该Java对象。
为了能够正确地进行序列化和反序列化,确保Person
类拥有与JSON数据结构对应的属性以及正确的getter和setter方法。
如果去掉参数上的@ResponseBody,将接收不到JSON
对象数据。
3.6、获取URL中参数 @PathVariable
-
通常有两种传参:
- @PathVariablea、path(url):/user/123;通过路径传递的参数,在URL的路径部分进行传递。
- @RequestPram:/user?id=123。是通过查询字符串(Query String)传递的参数,在URL的查询字符串部分进行传递。
第一种方式的优点:
1.搜索引擎抓取关键字权重更高,比如在百度上搜索123,会先显示第一种的url数据。
2.url更简洁
@PathVariable获取参数,在文章@RequestMapping阶段有说明过。
实现代码:
@RequestMapping("/reg/{name}/{pwd}")
public String reg(@PathVariable String name,@PathVariable String pwd){
return name+ ": "+ pwd;
}
前端实现:
注意:此时参数传参位置要和后端参数顺序位置一致。
3.7、上传文件@RequestPart
代码实现:
@RequestMapping("/load")
public boolean upload(@RequestPart("file")MultipartFile file){
//构造文件名
String fileName = UUID.randomUUID()+//文件名(随机值)
file.getOriginalFilename()//获取原文件名
.substring(file.getOriginalFilename()//从原文件后缀.截取
.lastIndexOf("."));//文件后缀(包含“.”)
//文件保存地址
File saveFile = new File("D:\\"+fileName);
try {
//保存文件
file.transferTo(saveFile);
return true;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
上述代码uploadFile()
方法使用@RequestPart
注解来接收名为"file"的表单项,其中MultipartFile
参数类型用于接收上传的文件内容。
文件名:UUID生成的随机值+从原文件名的后缀”.“开始截取(包含“.”),拼接成新的文件名。
使用postman上传文件:
**上传结果:**这是典型的UUID生成的
注意:上传文件是有限制大小的,默认为1M
,超过这个大小,会报错。
可以在配置文件(.properties)中进行配置:
spring.servlet.multipart.max-file-size=10MB
上述示例中,max-file-size
属性设置每个文件的最大大小限制。
4、获取Cookie/Session/Header
4.1、@CookieValue
使用@CookieValue注解获取Cookie
@RequestMapping("/getcok")
public String getCookie(@CookieValue("myCookie") String mk){
return "cookie :" + mk;
}
在上面的示例中,getCookie
方法使用@CookieValue
注解来接收名为"myCookie"的Cookie值,并将其存储在mk
参数中。要确保请求中包含指定名称的Cookie,否则@CookieValue
将无法获取到对应的值。
如果希望没有获取到Cookie时不报错,需要设置required = false
。
@RequestMapping("/getcok")
public String getCookie(@CookieValue(value = "myCookie",required = false) String mk){
return "cookie :" + mk;
}
运行结果:
4.2、@RequestHeader
使用@RequestHeader获取Header,使用方法和@CookieValue相似
@RequestMapping("/hd")
public String getHeader(@RequestHeader(value = "myHeader",required = false) String hd){
return "header :" + hd;
}
运行结果:
4.3、@SessionAttribute
要获取Session得现有Session,所以先存储一个Session:
private static final String SESSION_KEY = "SESSION";
@RequestMapping("/setsession")
public void doPostConstruct(HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute(SESSION_KEY,"zhangsan");//存储session
}
使用@SessionAttribute获取Session:
@RequestMapping("/getSe")
public String getSession(@SessionAttribute(SESSION_KEY) String mySe){
return mySe;
}
上述代码中,getSession
方法使用@SessionAttribute
注解来绑定SESSION_KEY
会话名称,并将接收到的值,赋值给mySe
中。确保会话属性的名称与@SessionAttribute
注解中指定的名称一致。
先访问路由,设置Session:
获取Session:
5、返回数据
5.1、返回静态页面
创建前端index.html
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>我是静态页面</h1>
</body>
</html>
创建controller
@Controller
@RequestMapping("/test")
public class IndexController {
@RequestMapping("/index")
public Object index(){
//...
return "/index.html";
}
}
上述代码中,是没有加@ResponseBody
注解的,所以默认返回是静态页面。注意,如果返回结果没有加/
是在当前目录(/test)下找index.html
,是会报400错误的,找不到。加/
代表的是在根目录下找index.html
,因为idex.html
是放在根目录(域名+端口号)下的。
运行结果:
5.2、返回text/html
代码:
@RequestMapping("/m")
@ResponseBody
public String method() {
return "<h1>Hello,HTML~</h1>";
}
访问结果:
5.3、返回JSON对象
@ResponseBody可以加在类或方法上,框架是会根据返回结果进行自动适配一个合适的类型。
@RequestMapping("/m8")
@ResponseBody
public HashMap<String, String> method_8() {
HashMap<String, String> map = new HashMap<>();
map.put("Java", "Java Value");
map.put("MySQL", "MySQL Value");
map.put("Redis", "Redis Value");
return map;
}
访问结果:
6、请求转发 / 请求重定向
Forward (请求转发转发):
- 在服务器内部进行页面跳转。
- 客户端发送请求给服务器,服务器将请求转发给另一个资源(如Servlet或JSP)进行处理,并将该资源的响应返回给客户端。
- 转发时,URL地址栏上的URL不会改变。
- 可以共享同一次请求的数据,如请求属性和会话属性。
- 适合在相同应用程序内部的页面跳转,可以保持更多的上下文信息和状态
Redirect (请求重定向):
- 在客户端浏览器中发起一个新的请求并重定向到新的URL。
- 客户端发送请求给服务器,服务器返回一个特殊的响应,包含HTTP状态码302和要跳转的目标URL。
- 浏览器接收到响应后,自动发起新的GET请求来获取跳转后的页面。
- 重定向后,浏览器的URL地址栏中会显示跳转后的URL。
- 不同请求之间无法直接共享数据,需要通过查询参数、表单参数等方式传递数据。
- 可以用于页面跳转、避免表单重复提交等场景。
区别:
-
请求方不同:请求重定向(redirect)客户端转发;请求转发(forward)服务器端转发。
-
最终URL地址不同:请求重定向地址发⽣变化,请求转发地址不发⽣变化。
-
数据共享不同:请求转发是服务器端实现的,所以整个执行流程中,客户端(浏览器端)只需要发送一次请求,因此整个交互过程中使用的都是同一个 Request 请求对象和一个 Response 响应对象,所以整个请求过程中,请求和返回的数据是共享的;而请求重定向客户端发送两次完全不同的请求,所以两次请求中的数据是不同的。
代码:
// 请求重定向
@RequestMapping("/index")
public String index(){
return "redirect:/index.html";
}
// 请求转发
@RequestMapping("/index2")
public String index2(){
return "forward:/index.html";
}
请求转发运行结果:当返回结果啥都不写,如 return "/index.html";
相当于return "forward:/index.html";
效果是一样的。
请求重定向结果:访问http://localhost:8080/test/index
后,地址变了
7、@ResponseBody / @RestController
- @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成application/json 返回给前端。
- @ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者json,⽽不是视图。
- @RestController = @Controller + @ResponseBody
具体来说,当一个控制器方法被@ResponseBody注解标记时,Spring会将方法的返回值序列化成HTTP响应的内容,并直接发送给客户端。框架会根据请求的Content-Type和适用的消息转换器将返回值转换为相应的格式,如JSON、XML等。
- 序列化: 序列化是指将对象转换为字节序列的过程。在序列化过程中,对象的状态(即对象的数据)被保存到字节流中,以便将来可以通过反序列化重新创建相同的对象。
- 反序列化: 反序列化是指从字节序列中恢复对象的过程。通过反序列化,可以将先前序列化的对象字节流转换回原始对象,恢复其状态和行为。