如何学习 Spring MVC?
学习 SPring MVC 只需要掌握以下三个功能:
- 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们 Spring程序;
- 获取参数的功能:用户访问的时候会带一些参数,在程序中要想办法获取到参数;
- 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。
目录
一,SPring MVC
1,什么是SPring MVC
MVC的定义
2,MVC 和 SPring MVC 的关系
二,SPring MVC 的创建和连接
1,创建 SPring MVC 项目
2,@RequestMapping注解介绍
2.1 @RequestMapping是post请求还是get请求
2.2 @GetMapping 和 @PostMapping
三,获取参数
1,传递单个参数
2,传递对象
3,参数重命名
4,接收 JSON 对象
5,获取 URL 中的参数
6,上传文件
7,获取Cookie
8,获取Header
9,获取Session
四,返回数据
1,返回静态页面
编辑
2,返回text/html
五,案例练习
1,实现计算器的相加功能
2,实现登录功能
一,SPring MVC
1,什么是SPring MVC
Spring MVC是基于Servlet API构建的原始Web框架,一开始包含在Spring框架中;它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但通常被称为“Spring MVC”。
- Spring MVC 是一个 Web 框架
- Spring MVC 是基于 Servlet API 构建的(所以包含Servlet的基本属性)
MVC的定义
MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
- Model(模型):是应用程序中用于处理应用程序数据逻辑的部分;通常模型对象负责在数据库中存取数据;
- View(视图):是应用程序中处理数据显示的部分;通常视图是依据模型数据创建的;
- Controller(控制器):是应用程序中处理用户交互的部分;通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
2,MVC 和 SPring MVC 的关系
MVC 是一种思想,而 SPring MVC 是对 MVC 思想的具体实现(这里类似于IoC是一种思想,DI是对IoC思想的具体实现);总结来说,SPring MVC 是一个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架,既然是 Web 框架,那么当用户在浏览器中输入 URL 之后,我们的 SPring MVC 项目就可以感知到用户的请求。
二,SPring MVC 的创建和连接
SPring MVC 项目创建和 SPring Boot创建项目相同(SPring MVC 使用 SPring Boot 的方式创建),在创建的时候选择Spring Web 就相当于创建了 SPring MVC 的项目。在 SPring MVC 中使用 @RequestMapping 注解来是西安 URL 路由映射,也就是浏览器连接程序的作用。
1,创建 SPring MVC 项目
Spring Boot 项目创建的详细过程可以参考之前的博文:SpringBoot项目的创建和使用_蜡笔小心眼子!的博客-CSDN博客
接下来,创建一个TestController类,实现用户到Spring程序的互联互通,代码如下:
package com.example.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller//让Spring框架启动时加载该类
@ResponseBody//返回非页面数据
public class TestController {
@RequestMapping("/sayhi")
//该注解是路由规则 映射浏览器输入的URL
public String sayHi() {
return "hello world";
}
}
在浏览器输入“localhost:8080/sayhi"(因为Spring MVC默认情况下的端口号是8080),就可以访问到该后端方法并打印相关信息了:
2,@RequestMapping注解介绍
@RequestMapping 是 SPring Web 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的(路由映射:指的是当用户访问一个URL时,将用户的请求对应到程序中某个类的某个方法的过程就叫做路由映射);@RequestMapping既可以修饰类也可以修饰方法。
2.1 @RequestMapping是post请求还是get请求
使用Postman测试@RequestMapping是否可以接受 Get 或 Post请求:
测试Get:
测试Post:
所以@RequestMapping既可以接收Post请求也可以接收Get请求!
2.2 @GetMapping 和 @PostMapping
上面测试出@RequestMapping既可以接收Post请求也可以接收Get请求,那么如果只想接收某种单一的请求该怎么办呢?此时就需要用到其他注解:@GetMapping(只接收Get请求) 和 @PostMapping(只接收Post请求)或者在@RequestMapping注解中设置参数确定接收某种请求。
Get 请求的三种写法:
//写法1
@RequestMappin("/sayhi")
//写法2
@RequestMapping(value = "/sayhi",method = RequestMethod.GET)
//写法3
@GetMapping("/sayhi")
Post 请求的两种写法:
//写法1
@RequestMapping(value = "/sayhi",method = RequestMethod.Post)
//写法2
@PostMapping("/sayhi")
三,获取参数
1,传递单个参数
@RequestMapping("/say")
public String say(String name) {
return "hi " + name;
}
注意:在say方法中的参数的类型一定要设置成引用类型,因为设置成引用类型之后即使你在url中没有传入该参数最多查询的数据为null,如果是基本类型的话则会直接报错!
2,传递对象
@Data //包含了lombok的多个注解
public class Userinfo {
private int id;
private String name;
private int age;
}
@RequestMapping("userinfo")
public Userinfo getUserinfo(Userinfo userinfo) {
log.info(String.valueOf(userinfo));
return userinfo;
}
注意:返回的对象在前端页面中是以JSON的格式进行展示的!
3,参数重命名
假设前端输入的参数名是username,后端不想使用该参数名,可以通过重命名的方式(使用@RequestParam注解)将其改成自己想要的参数名如:name
@RequestMapping("/sayhi2")
public String sayHi2(@RequestParam(value = "username", required = false) String name,
@RequestParam(value = "pass", required = false) String password) {
//required = false 表示url中输入的参数名不匹配时默认为null
return "name: " + name + " password: " + password;
}
注意:@RequestParam注解中可以设置required变量为false(说明如果没有输入username这个变量就会返回null,默认是true,此时没有输入变量的情况下会直接报错,所以一般都会将其设置成false)
4,接收 JSON 对象
JSON对象需要通过Postman进行构造
@RequestMapping("/getjson")
//接受 JSON 格式的数据必须加上 @RequestBody 注解
public Object getJson(@RequestBody Userinfo userinfo) {
log.info(String.valueOf(userinfo));
return userinfo;
}
注意:获取JSON格式的数据时必须在参数名前面加上 @RequestBody否则获取到的则是默认零值!
5,获取 URL 中的参数
@RequestMapping("/geturl/{name}/{password}")
public String getUrl(@PathVariable String name, @PathVariable String password) {
return "name: " + name + " password: " + password;
}
注意:
- 在路由中需要用{}设置参数名;
- 在参数名前要加上@PathVariable注解.
6,上传文件
假设此时需要上传一张图片,需要在配置文件中设置需要保存的地址然后通过Postman来进行上传
//配置文件
imgpath:D:\\Users\\date\\
//从配置文件中读取到文件的保存路径
@Value("${imgpath}")
private String imgpath;
@RequestMapping("/upimg")
public boolean upimg(Integer id, @RequestPart("img") MultipartFile file) {
boolean result = false;
//1.目录
//2.图片名称(图片名不能重复)[UUID]
//3.获取原上传图片的格式
String fileName = file.getOriginalFilename();//得到原图片的名称
fileName = fileName.substring(fileName.lastIndexOf("."));//得到图片后缀
fileName = UUID.randomUUID().toString() + fileName;
//保存图片到本地目录
try {
file.transferTo(new File(imgpath + fileName));
result = true;
} catch (IOException e) {
log.error("图片上传失败: " + e.getMessage());
}
return result;
}
7,获取Cookie
获取Cookie之前需要提前在控制台(F12打开控制台)输入一个Cookie,方式如下:
//方法一:通过 HttpServletRequest 获取所有的cookie
@RequestMapping("/cookie")
public void getCookie(HttpServletRequest request) {
//获取所有的cookie
Cookie[] cookies = request.getCookies();
for (Cookie item: cookies) {
log.info("CookieName: " + item.getName() + " CookieValue: " + item.getValue());
}
}
//方法二:通过注解获取指定cookie
@RequestMapping("/cookie2")
public String getCookie2(@CookieValue("bit") String cookie) {
return "CookieValue: " + cookie;
}
方式一:
方式二:
8,获取Header
//方法一:通过 HttpServletRequest
@RequestMapping("/header")
public String getHeader(HttpServletRequest request) {
return request.getHeader("User-agent");
}
//方法二:通过注解
@RequestMapping("/header2")
public String getHeader2(@RequestHeader("User-agent") String userAgent) {
return userAgent;
}
方式一:
方式二:
9,获取Session
获取Session之前需要先存储一个Session,代码如下:
//session的存储
@RequestMapping("/setsess")
public boolean setSession(HttpServletRequest request) {
boolean result = false;
HttpSession session = request.getSession(true);//没有就创建一个会话
session.setAttribute("userinfo","张三");
result = true;
return result;
}
获取Session代码如下:
//方法一:通过 HttpServletRequest 获取
@RequestMapping("/getsess")
public String getSession(HttpServletRequest request) {
String result = null;
HttpSession session = request.getSession(false);
if(session != null && session.getAttribute("userinfo") != null) {
result = (String) session.getAttribute("userinfo");
}
return result;
}
//方法二:通过注解获取
@RequestMapping("/getsess2")
public String getSession2(@SessionAttribute(value = "userinfo",required = false) String userinfo) {
return userinfo;
}
方式一:
方式二:
四,返回数据
通过上面的学习,默认请求下无论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),而现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使用@ResponseBody 注解了。
1,返回静态页面
创建前端页面 hello.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.
0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>hello,spring mvc</title>
<script src="index.js"></script>
</head>
<body>
<h1>Hello,Spring MVC.</h1>
</body>
</html>
2,返回text/html
@RequestMapping("/aaa")
public String print() {
return "<h1>Hello Spring MVC</h1>";
}
五,案例练习
1,实现计算器的相加功能
可使用Postman传递参数,或使用form表单的方式提交参数;
前端页面:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.
0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>计算器示例</title>
</head>
<body>
<form action="/calc">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
后端代码:
package com.example.demo.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CalcController {
@RequestMapping("/calc")
public String calc(Integer num1,Integer num2) {
if(num1 == null || num2 == null) {
return "<h1>参数错误!</h1><a href='javascript:history.go(-1);'>返回</a>";
}
return "<h1>结果: " + (num1 + num2) + "</h1><a href='javascript:history.go(-1);'>返回</a>";
}
}
2,实现登录功能
前端使用ajax,后端返回json给前端;
前端代码:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="js/jquery-1.9.1.min.js"></script>
<title>Document</title>
<script>
// ajax 提交
function mysub(){
// 1.判空
var username = jQuery("#username");
var password = jQuery("#password");
if(jQuery.trim(username.val())==""){
alert("请先输入用户名!");
username.focus(); // 光标重制到此元素
return;
}
if(jQuery.trim(password.val())==""){
alert("请先输入密码!");
password.focus(); // 光标重制到此元素
return;
}
jQuery.ajax({
url:"/user/login3",
type:"POST",
contentType:"application/json",
data:JSON.stringify({"username":username.val(),
"password":password.val()}),
success:function(result){
alert(JSON.stringify(result));
}
});
}
</script>
</head>
<body>
<div style="text-align: center;">
<h1>登录</h1>
用户:<input id="username">
<br>
密码:<input id="password" type="password">
<br>
<input type="button" value=" 提交 " onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
</div>
</body>
</html>
后端代码:
@RequestMapping(value = "/login")
@ResponseBody
public HashMap<String,Object> login(String username, String password){
HashMap<String,Object> res = new HashMap<>();
int succ = 200;
if(username!=null && password!=null &&
username.equals("admin") && password.equals("admin")){
res.put("msg","登录成功");
} else{
res.put("msg","登录失败");
}
res.put("succ",succ);
return res;
}