JavaEE--Spring MVC
目录
一、Spring MVC概述
二、建立连接
1. @RequestController注解
2. @RequestMapping注解
3. Postman
3.1 下载与安装
3.2 创建请求
编辑
三、请求
1. 传递单个参数
2. 传递多个参数
3. 传递对象
4. 后端参数重命名
5. 传递数组
6. 传递集合
7. 传递JSON数据
7.1 JSON概念
7.2 JSON 语法规则
7.3 JSON 与 Java 对象互转
7.4 JSON优点
7.5 传递JSON对象
8. 从URL中获取参数
9. 上传文件
10. 获取Cookie
11. 获取session
12. 获取Header
四、响应
1. 返回静态页面
2. 返回数据
3. 返回HTML代码片段
4. 返回JSON
5. 设置状态码
6. 设置Header
一、Spring MVC概述
官网https://docs.spring.io/spring-framework/reference/web/webmvc.html
Spring MVC 是 Spring 框架的一个模块,专门用于构建基于 Java 的 Web 应用程序。它基于模型-视图-控制器(MVC)设计模式,提供了一种灵活、可扩展的方式来开发动态网页应用。
简单来说,Spring MVC是一个Web框架。
既然是Web框架,那么当用户在浏览器中输入了url之后,我们的Spring MVC项目就可以感知到用户的请求,并给予响应。
学习Spring MVC,也就是学习如何通过浏览器和用户程序进行交互。
交互主要分以下三个方面:
- 建立连接:将用户(浏览器)和Java程序连接起来,也就是访问一个地址能够调用到我们的Spring程序;
- 请求:用户请求的时候会带一些参数,在程序中要想办法获取到参数,所以请求主要是获取参数的功能;
- 响应:执行了业务逻辑之后,要把程序执行的结果返回给用户。
二、建立连接
在Spring MVC中使用@RequestMapping注解来是想URL路由映射,也就是浏览器连接程序的作用。
先创建一个Spring Boot项目,再创建一个UserController类,实现用户通过浏览器和程序的交互,代码如下:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HelloController {@RequestMapping("/hello")public String hello() {return "Hello World";}
}
方法名和路径名无需一致。
运行程序后,接下来在浏览器访问http://127.0.0.1:8080/hello:
1. @RequestController注解
@RequestController是 Spring MVC 中的一个组合注解,主要用于简化 RESTful Web 服务的开发,将方法的返回值直接序列化为 JSON 或 XML 响应体,无需额外的视图解析。
核心特性:
- 自动将方法返回值转换为 HTTP 响应体。
- 默认使用@ResponseBody注解效果,无需显式声明。
- 适用于返回 JSON/XML 数据的 API 场景。
2. @RequestMapping注解
@RequestMapping是Spring MVC应用程序中最常被用到的注解之一,用来注册接口的路由映射。
当服务收到请求时,路径为/hello的请求就会调用hello这个方法的代码。
路由映射:当用户访问一个URL时,将用户的请求对应到程序中某个类的某个方法的过程。
@RequestMapping既可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类路径+方法路径。
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RequestMapping("/Spring")
@RestController
public class HelloController {@RequestMapping("/hello")public String hello() {return "Hello World";}
}
访问地址:http://127.0.0.1:8080/Spring/hello
@RequestMapping的URL路径最前面加不加/(斜杠)都可以,Spring程序启动时,会进行判断,如果前面没有加/,Spring会拼接上一个/。
@RequestMapping的URL路径也可以是多层路径,最终访问时,依然是类路径+方法路径。
@RequestMapping("/Spring/1")
@RestController
public class HelloController {@RequestMapping("/hello/2")public String hello() {return "Hello World";}
}
访问地址:http://127.0.0.1:8080/Spring/1/hello/2
@RequestMapping既支持Get请求,又支持Post请求。同理,也支持其他的请求方式。可以通过method参数或者@GetMapping/@PostMapping来指定。
import org.springframework.web.bind.annotation.*;@RequestMapping("user")
@RestController
public class UserController {//既支持get,又支持post@RequestMapping("/m1")public String m1() {return "m1";}//只支持get@RequestMapping(value = "/m2", method = RequestMethod.GET)public String m2() {return "m2";}//相当于@GetMapping("/m4")public String m4() {return "m4";}//只支持post@RequestMapping(value = "/m3", method = RequestMethod.POST)public String m3() {return "m3";}//相当于@PostMapping("/m5")public String m5() {return "m5";}
}
3. Postman
为了更加方便的测试后端方法,我们可以使用 API 开发与测试工具--Postman。
3.1 下载与安装
在官网下载,安装过程很简单,这里就不赘述了。
3.2 创建请求
如何操作:
普通传参,也就是通过查询字符串来传参。
学习HTTP环节时,我们通过URL来访问互联网上的某一个资源,URL的格式如下:
其中,查询字符串就是请求的参数。
在Postman上可以这样设置:
与此同时,URL也会变化:
三、请求
访问不同的路径,就是发送不同的请求.在发送请求时,可能会带一些参数,所以学习Spring的请求,主要是学习如何传递参数到后端以及后端如何接收。
1. 传递单个参数
传递单个参数,在SpringMVC中直接用方法中的参数就可以,比如以下代码:
@RequestMapping("/request")
@RestController
public class RequestController {@RequestMapping("/r1")public String r1(String keyword){return "接收参数:" + keyword;}
}
可以在URL中自定义keyword=spring访问地址:
也可以使用Postman:
先输入URL:
再输入参数:
点击send:
可以看到,后端程序正确地拿到了参数值。
注意事项:
- 参数名一定要一致;
- 使用基本类型来接收参数时,参数必须传(除boolean类型),否则会报500错误类型,不匹配时,会报400错误类型,所以企业开发中,对于参数可能为空的数据,建议使用包装类型。
包装类 基本数据类型 代码 @RequestMapping("/r3") public String r3(Integer number){return "接收参数: " + number; }
@RequestMapping("/r4") public String r4(int number){return "接收参数: " + number; }
正常传参 非正常传参
2. 传递多个参数
@RequestMapping("/r2")
public String r2(String username, String password){return "接收参数: username:" + username + ", password:" + password;
}
URL中参数的顺序可以调换,不影响正常传参。
3. 传递对象
创建一个UserInfo对象类:
public class UserInfo {private String name;private Integer gender;private Integer age;public UserInfo(){}public UserInfo(String name, Integer age, Integer gender) {this.age = age;this.gender = gender;this.name = name;}public Integer getGender() {return gender;}public void setGender(Integer gender) {this.gender = gender;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "UserInfo{" +"age=" + age +", name='" + name + '\'' +", gender=" + gender +'}';}
}
传参代码:
@RequestMapping("/r5")
public String r5(UserInfo userInfo){return "接收参数: " + userInfo.toString();
}
Spring会根据参数名称自动绑定到对象的各个属性上,如果某个属性未传递,则赋值为null(基本类型则赋值为默认初识值,比如int类型的属性,会被赋值为0)。
4. 后端参数重命名
某些特殊的情况下,前端传递的参数key和我们后端接收的key可以不一致,比如前端传递了一个q给后端,而后端是使用keyword字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用@RequestParam来重命名前后端的参数值。
//此时q为必传参数
@RequestMapping("/r6")
public String r6(@RequestParam("q") String keyword){return "接收参数: keyword=" + keyword;
}
//此时q为非必传参数
@RequestMapping("/r7")
public String r7(@RequestParam(value = "q", required = false) String keyword){return "接收参数: keyword=" + keyword;
}
5. 传递数组
//传递数组
@RequestMapping("/r8")
public String r8(String[] arr){return "接收参数:arr=" + Arrays.toString(arr);
}
可以用‘,’,也可以一个一个地传递。
6. 传递集合
和数组类似,同一个请求参数名有为多个,且需要使用@RequestParam绑定参数关系。
//传递集合
@RequestMapping("/r9")
public String r9(@RequestParam List<Integer> list){return "接收参数:list=" + list;
}
7. 传递JSON数据
7.1 JSON概念
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,采用文本格式存储和传输数据,易于人阅读和编写,也便于机器解析和生成。它基于 ECMAScript 的子集,但独立于编程语言,广泛用于 Web 应用和 API 交互。
7.2 JSON 语法规则
- 数据以键值对形式表示,键名用双引号包裹,例如
"name": "Alice"
。 - 数据之间用逗号分隔,例如
{"name": "Alice", "age": 25}
。 - 花括号
{}
表示对象(Object),方括号[]
表示数组(Array)。 - 支持的数据类型:字符串、数字、布尔值、对象、数组、
null
。
{"name": "Alice","age": 30,"isStudent": false,"hobbies": ["reading", "coding"],"address": {"city": "New York","country": "USA"}
}
7.3 JSON 与 Java 对象互转
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;public class JsonTest {@Testvoid testObject2Json() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();//创建java对象UserInfo userInfo = new UserInfo("zhangsan", 15, 1);//对象转jsonString s = objectMapper.writeValueAsString(userInfo);System.out.println(s);}@Testvoid testJson2Object() throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();//创建Json字符串String s = "{\"name\":\"ZhangSan\",\"gender\":1,\"age\":15}";//Json转对象UserInfo userInfo = objectMapper.readValue(s, UserInfo.class);System.out.println(userInfo);}
}
7.4 JSON优点
- 简单易用:语法简单,易于理解和编写,可以快速地进行数据交换。
- 跨平台支持:JSON可以被多种编程语言解析和生成,可以在不同的平台和语言之间进行数据交换和传输。
- 轻量级:相较于XML格式,JSON数据格式更加轻量级,传输数据时占用带宽较小,可以提高数据传输速度。
- 易于扩展:JSON的数据结构灵活,支持嵌套对象和数组等复杂的数据结构,便于扩展和使用。
- 安全性:JSON数据格式是一种纯文本格式,不包含可执行代码,不会执行恶意代码,因此具有较高的安全性。
7.5 传递JSON对象
传递JSON对象,需要使用@RequestBody注解。
//传递Json
@RequestMapping("/r10")
public String r10(@RequestBody UserInfo userInfo){return "接收参数:" + userInfo.toString();
}
8. 从URL中获取参数
需要在参数前添加@PathVariable注解。
//从url中获取参数
@RequestMapping("/article/{articleID}")
public String r11(@PathVariable Integer articleID){return "接收文章ID:" + articleID;
}
也可以获取多个参数(没有按照顺序也能正确执行)。
@RequestMapping("/article/{type}/{articleID}")
public String r12(@PathVariable Integer articleID, @PathVariable String type){return "接收文章ID:" + articleID + ",type: " + type;
}
9. 上传文件
文件参数类型使用MultipartFile。
@RequestMapping("/r13")
public String r13(MultipartFile file) throws IOException {file.transferTo(new File("D:\\temp\\" + file.getOriginalFilename()));return "文件上传成功: " + file.getOriginalFilename();
}
点击“+ New file from local machine”,在本地选择你要上传的文件。
点击send。
D盘temp文件夹中也成功出现了我们想要上传的文件。
10. 获取Cookie
设置Cookie
保存,就获得另一个Cookie。
也可以添加多个Cookie值。
方法一:
@RequestMapping("/r14")
public String r14(HttpServletRequest request, HttpServletResponse response){Cookie[] cookies = request.getCookies();if (cookies != null) {for (Cookie cookie: cookies) {System.out.println(cookie.getName() + ':' + cookie.getValue());}}return "返回Cookie成功!";
}
request:请求,response:响应
这两个参数不是绑定出现的,所以以上代码可以不用谢response。
方法二:
@RequestMapping("/r15")
public String r15(@CookieValue("name") String name) {return "从注解获取到name的值:" + name;
}
这种方法虽然简洁,但是一次只能获取到一个Cookie值。
11. 获取session
Session是服务器端的机制,我们需要先存储,才能再获取。
//session存储
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request) {//从Cookie中获取SessionID,再根据SessionID获取Session对象HttpSession session = request.getSession();//session默认存储在内存中session.setAttribute("name", "zhangsan");session.setAttribute("age", 15);return "session存储成功!";
}
获取session有两种方式:
HttpSession getSession(boolean create);HttpSession getSesion();
参数如果为true,则当不存在会话是新建会话;参数如果为false,则当不存在会话时返回null。
方法一:
//获取session
@RequestMapping("/getSession")
public String getSession(HttpServletRequest request) {HttpSession session = request.getSession(false);//若用户登录,session有值,用户未登录,session为nullif (session == null) {return "用户未登录";} else {String name = (String) session.getAttribute("name");return "登录用户为:" + name;}
}
方法二:
@RequestMapping("/getSession2")
public String getSession2(HttpSession session) {//相当于getSession参数为true,则不存在session为null的情况String name = (String) session.getAttribute("name");return "登录用户为:" + name;
}
方法三:
@RequestMapping("/getSession3")
public String getSession3(@SessionAttribute("name") String name) {return "登录用户为:" + name;
}
12. 获取Header
方法一:
//获取Header
@RequestMapping("/getHeader")
public String getHeader(HttpServletRequest request) {String userAgent = request.getHeader("User-Agent");return "从header获取userAgent:" + userAgent;
}
方法二:
@RequestMapping("/getHeader2")
public String getHeader2(@RequestHeader("User-Agent") String userAgent) {return "从header获取userAgent:" + userAgent;
}
四、响应
1. 返回静态页面
先创建前端页面,注意在resources/static/路径下创建。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<h1>我是Index页面</h1>
</body>
</html>
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@RequestMapping("/resp")
@Controller
public class RespController {//返回页面@RequestMapping("/r1")public String returnPage(){return "/index.html";}
}
但若是把类注解写成@RestController,那么运行之后却发现,页面未正确返回,http响应把"/index.html"当做了http响应正文的数据。
随着互联网的发展,目前项目开发流行"前后端分离"模式,Java主要是用来做后端项目的开发,所以也就不再处理前端相关的内容了。MVC的概念也逐渐发生了变化,View不再返回视图,而是返回显示视图时需要的数据。所以前面使用的@RestController其实是返回的数据。
而@RestController=@Controller+@ResponseBody+……
//@RestController源码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {@AliasFor(annotation = Controller.class)String value() default "";
}
@ResponseBody既是类注解,又是方法注解。作为类注解的时候,表示该类的所有方法全部返回数据,作为方法注解时,表示该方法返回数据。
如果一个类全部返回数据,可以使用@RestController或者@Controller+@ResponseBody;
如果一个类全部返回页面,使用@Controller。
2. 返回数据
//返回数据
@ResponseBody
@RequestMapping("/r2")
public String returnData() {return "我是前端需要的数据";
}
3. 返回HTML代码片段
@ResponseBody
@RequestMapping("/r3")
public String returnHTML() {return "<h1>我是一级标题</h1>";
}
也可以使用produces设置响应的Content-type:
@ResponseBody
@RequestMapping(value = "/r4", produces = "text/plain")
public String returnHTML2() {return "<h1>我是一级标题</h1>";
}
4. 返回JSON
@ResponseBody
@RequestMapping("/r5")
public UserInfo returnJSON() {return new UserInfo("zhangsan", 20, 1);
}
5. 设置状态码
@ResponseBody
@RequestMapping("/r6")
public UserInfo setStatus(HttpServletResponse response) {response.setStatus(401);return new UserInfo("zhangsan", 20, 1);
}
使用postman观察,可以看出,状态码不影响页面的显示。
6. 设置Header
@ResponseBody
@RequestMapping("/r7")
public String setHeader(HttpServletResponse response) {response.setHeader("myHeader", "myHeader");return "设置Header成功";
}
创作不易,给个三连支持一下吧