目录
7.3@RequestMapping 是 post 还是 get 请求?
1.什么是SpringMVC?
我们可以从官网看下对于SpringMVC的描述:
Spring Web MVC :: Spring Framework
翻译为中文:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。它的 正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC”。
从上述定义我们可以得出两个关键信息:
1. Spring MVC 是一个 Web 框架。
2. Spring MVC 是基于 Servlet API 构建的。
2.SpringMVC的作用
Spring MVC是一个基于Java的实现了MVC设计模式的请求驱动类型的轻量级Web框架,通过把Model,View,Controller分离,将web层进行职责解耦,把复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
MVC模式(Model-View-Controller):解决页面代码和后台代码的分离。
3.SpringMVC的原理
在没有使用SpringMVC之前我们都是使用Servlet在做Web开发。但是使用Servlet开发在接收请求参数,数据共享,页面跳转等操作相对比较复杂。servlet是java进行web开发的标准,既然springMVC是对servlet的封装,那么很显然SpringMVC底层就是Servlet,SpringMVC就是对Servlet进行深层次的封装。
4.MVC模式
在上面我们提到了MVC模式,那么到底什么是MVC模式呢?
MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构模式,它把软件系统分为模型model(javabean)、视图view(jsp/img)、控制器Controller(Action/servlet)三个基本部分。
我们可以这样理解:
控制器存在的目的就是为了保证模型和视图的一致性,当模型发生改变时,控制器可以把模型中的新内容更新到视图中。
1.Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数 据。
2.View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
3.Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户 输入,并向模型发送数据。
5.SpringMVC的执行流程和原理
上面的图只是展示出了 SpringMVC 的 MVC 三部分的处理情况
那么SpringMVC涉及到了哪些组件呢?以及SpringMVC执行流程和原理到底是什么呢?
--涉及组件分析:
1、前端控制器DispatcherServlet由框架提供,在web.xml中配置。
作用:接收请求,响应结果,相当于转发器,中央处理器。
2、处理器映射器HandlerMapping)由框架提供。
作用:根据请求的url查找Handler(处理器/Controller),可以通过XML和注解方式来映射。
3、处理器适配器HandlerAdapter由框架提供。
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler中的方法。
4、处理器Handler(也称之为Controller,需要程序员开发)
注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler。
作用:接受用户请求信息,调用业务方法处理请求,也称之为后端控制器。
5、视图解析器ViewResolver由框架提供。
作用:进行视图解析,把逻辑视图解析成真正的物理视图。
SpringMVC框架支持多种View视图技术,包括:jstlView、freemarkerView、ThymeleafView等。
6、视图View(需要工程师开发)
作用:把数据展现给用户的页面
View是一个接口,实现类支持不同的View技术(jsp、freemarker、pdf等)
--SpringMVC执行流程:
1.用户发送请求至前端控制器DispatcherServlet
2.DispatcherServlet收到请求调用处理器映射器HandlerMapping。
3.处理器映射器根据请求url找到具体的处理器,生成处理器执行链HandlerExecutionChain(包括处理器对象和处理器拦截器)一并返回给DispatcherServlet。
4.DispatcherServlet根据处理器Handler获取处理器适配器HandlerAdapter执行HandlerAdapter处理一系列的操作,如:参数封装,数据格式转换,数据验证等操作
5.执行处理器Handler(Controller,也叫页面控制器)。
6.Handler执行完成返回ModelAndView
7.HandlerAdapter将Handler执行结果ModelAndView返回到DispatcherServlet
8.DispatcherServlet将ModelAndView传给ViewReslover视图解析器
9.ViewReslover解析后返回具体View
10.DispatcherServlet对View进行渲染视图(即将模型数据model填充至视图中)。
11.DispatcherServlet响应用户。
6.如何学习SpringMVC?
说了这么多,我们到底应该怎样学习SpringMVC呢?
学习 Spring MVC 我们需要掌握以下 3 个功能:
1. 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的 Spring 程序。
2. 获取参数的功能:用户访问的时候会带一些参数,在程序中要想办法获取到参数。
3. 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。
对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC。
7.SpringMVC的创建和连接
Spring MVC 项目创建和 Spring Boot 创建项目相同(Spring MVC 使用 Spring Boot 的方式创建),在创建 的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。
7.1创建 Spring MVC 项目
Spring MVC 可以基于 Spring Boot 创建,也就是创建一个 Spring Boot 项目,勾选上 Spring Web 模块即 可,如下图所示:
接下来,创建一个 UserController 类,实现用户到 Spring 程序的互联互通,具体实现代码如下:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller // 让 spring 框架启动时,加载
@ResponseBody // 返回一个 text/html 信息
@RequestMapping("/user") // 路由器规则注册
public class UserController {
// 路由器规则注册
@RequestMapping("/hi")
public String sayHi(){
return "<h1>Hi,Spring MVC.</h1>";
}
}
这样实现之后,当访问地址:http://localhost:8080/user/hi 时就能打印“hello,spring mvc”的信息了。
7.2@RequestMapping 注解介绍
在介绍@RequestMapping 注解前,我们需要知道在我们SpringMVC项目中,最常用的注解有:
- @RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
- @RequestBody:注解实现接收http请求的json数据,将json转换为java对象。
- @ResponseBody:注解实现将conreoller方法返回对象转化为json对象响应给客户。
如果我们类上都需要@Controller和@ResponseBody这两个注解,那我们可以使用@RestController这一个注解来代替。
@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的。
路由映射:所谓的路由映射指的是,当用户访问一个 url 时,将用户的请求对应到程序中某个类的某个 方法的过程就叫路由映射。
@RequestMapping 即可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类 + 方法。 @RequestMapping 也可以直接修饰方法,代码实现如下:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
//标识该注解的类是一个Bean,且专门是负责web请求和响应处理的
@Controller
//定义请求的路径
//SpringMVC是一个类里面多个方法处理web请求
@ResponseBody//注解所有类的web方法,所有的返回值,都默认转换为json字符串
public class UseController {
//先简单实现,定义路径
@RequestMapping("/u1")
//定义方法:public Object 方法名(方法参数){return 返回值
//实例方法,返回值要让他变成json字符串,方法名随便取
public Object u1(){
Map<String,Object> map=new HashMap<>();
map.put("a",123);
map.put("b",true);
map.put("c","abc");
return map;
}
}
方法地址:http://localhost:8080/u1
7.3@RequestMapping 是 post 还是 get 请求?
@RequestMapping 默认是什么方式的请求呢?,可以使用 postman 进行测试。
postman下载地址:Postman API Platform | Sign Up for Free
上面的示例,当我们尝试使用 get 访问时,效果如下:
当我们尝试使用 post 访问时,效果如下:
总结:
(1)如果方法上的@RequestMapping注解没有设置method属性,则get和post请求默认都可以访问。
(2)如果方法上的@RequestMapping注解设置了method属性,则只能是相应的请求方式可以访问。
例如下面代码,设置对应的method属性:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
//标识该注解的类是一个Bean,且专门是负责web请求和响应处理的
@Controller
//定义请求的路径
//SpringMVC是一个类里面多个方法处理web请求
@ResponseBody//注解所有类的web方法,所有的返回值,都默认转换为json字符串
public class UseController {
//value是String[],可以写""一个,也可以写{"",""}多个
//method是RequestMethod[],其中RequestMethod是枚举类型
//只支持post请求方法
//(value = {"/u2","/u3"},method = RequestMethod.POST)
//支持post请求方法和get方法
//(value = {"/u2","/u3"},method = {RequestMethod.POST,RequestMethod.GET})
@RequestMapping(value = {"/u2","/u3"},method = {RequestMethod.GET})
public Object u2(){
Map<String,Object> map=new HashMap<>();
map.put("a",123);
map.put("b",true);
map.put("c","abc");
return map;
}
}
当我们尝试使用 get 访问时,效果如下:
当我们尝试使用 post 访问时,效果如下:
7.4@GetMapping 和 PostMapping
get 请求的 3 种写法:
// 写法1
@RequestMapping("/index")
// 写法2
@RequestMapping(value = "/index",method = RequestMethod.GET)
// 写法3
@GetMapping("/index")
post 请求的 2 种写法:
// 写法1
@RequestMapping("/index")
// 写法2
@RequestMapping(value = "/index",method = RequestMethod.POST)
// 写法3
@PostMapping("/index")
8.获取参数
8.1传递单个参数
在 Spring MVC 中可以直接用方法中的参数来实现传参,比如以下代码:
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class Demo {
@RequestMapping("/me1")
public Object method1(String name){
System.out.println("参数name:"+name);
return "/index.html";
}
}
在 postman 中访问方法:
程序的执行结果:
8.2传递对象
并且 Spring MVC 可以自动实现参数对象的赋值,比如 Person 对象:
import lombok.Data;
@Data
public class Person {
private int id;
private String name;
private String password;
}
传递对象代码实现:
@RequestMapping("/me2")
public Object method2(Person person){
System.out.println("person id :" + person.getId());
System.out.println("person name :" + person.getName());
System.out.println("person password :" + person.getPassword());
return "/index.html";
}
前端访问:
最终执行结果:
8.3表单参数传递/传递多个参数(非对象)
@RequestMapping("/me3")
public Object method3(String name, String pwd) {
System.out.println("name 参数:" + name);
System.out.println("pwd 参数:" + pwd);
return "/index.html";
}
前台访问地址:
最终执行结果:
重要说明:当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置 是不影响后端获取参数的结果。
8.4后端参数重命名(后端参数映射)
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不一致,比如前端传递了一个 time 给 后端,而后端又是有 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我 们就可以使用 @RequestParam 来重命名前后端的参数值。
具体示例如下,后端实现代码:
@RequestMapping("/me4")
public Object method4(@RequestParam("time") String createtime) {
System.out.println("时间:" + createtime);
return "/index.html";
}
前端访问地址:
最终执行结果:
8.5设置参数必传@RequestParam
上面的列子,如果我们是前端传递一个非 time 的参数,就会出现程序报错的情况,如下图所示:
这是因为后端已经声明了前端必须传递一个 time 的参数,但是前端没有给后端传递,我们查看 @RequestParam 注解的实现细节就可以发现端倪,注解实现如下:
required:必须的意思,默认值为true,因此不传递此参数会报400的错误
非必传参数设置:
如果我们的实际业务前端的参数是一个非必传的参数,我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错,具体实现如下:
8.6@RequestBody 接收JSON对象
后端接收代码:
@RequestMapping(value = "/me5", method = RequestMethod.POST)
public Object method5(@RequestBody Person person) {
System.out.println("Person:" + person);
return "redirect:/index.html";
}
前端访问:
当我们去除掉@RequestBody就可以发现输出不是json格式
8.7上传文件@RequestPart
@RequestMapping("/param9")
public String param9(String name, @RequestPart("myfile") MultipartFile file)
throws IOException {
// 获取文件后缀名
String fileName =
file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."
));
// 文件保存地址
String filePath =
ClassUtils.getDefaultClassLoader().getResource("static").getPath() +
"/" + UUID.randomUUID() + fileName;
// 保存文件
file.transferTo(new File(filePath));
return filePath + " 上传成功.";
}
获取项目目录的几种方式:
ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();
new ClassPathResource("").getFile().getAbsolutePath();
ClassUtils.getDefaultClassLoader().getResource("").getPath();
ResourceUtils.getFile("classpath:static/").getPath();
8.8获取Cookie/Session/header
传统获取 header/cookie:
@RequestMapping("/param10")
@ResponseBody
public String param10(HttpServletResponse response, HttpServletRequest request) {
String name = request.getParameter("name");
// 获取所有 cookie 信息
Cookie[] cookies = request.getCookies();
String userAgent = request.getHeader("User-Agent");
return name + ":"+userAgent;
}
简洁的获取 Cookie—@CookieValue:
@RequestMapping("/cookie")
@ResponseBody
public String cookie(@CookieValue("bite") String bite) {
return "cookie:" + bite;
}
简洁获取 Header—@RequestHeader:
@RequestMapping("/header")
@ResponseBody
public String header(@RequestHeader("User-Agent") String userAgent) {
return "userAgent:"+userAgent;
}
Session 存储和获取:
Session 存储和 Servlet 类似,是使用 HttpServletRequest 中获取的,如下代码所示:
//操作session:先模拟登录,设置一个用户会话
@RequestMapping("/login")
public Object login(HttpServletRequest request){
//模拟登录成功,登录的用户叫abc
//服务端会话管理的数据结构map.put(随机字符串,session);return session
HttpSession session = request.getSession();
session.setAttribute("user","abc");
Map<String,Object> map=new HashMap<>();
map.put("user","abc");
return map;
}
读取 Session 可以使用 HttpServletRequest,如下代码所示:
//操作session,获取session中的abc
//required = false是配置是否获取session必须的,如果配置为true,获取不到session就会报错,设置为false,不登陆也可以访问
//如果这个接口,必须登陆后访问,则不需要设置required,如果不登陆也要登录,就必须设置
//public Object getSession(@SessionAttribute(value = "user",required = false) String user)
@RequestMapping("/getSession")
public Object getSession(@SessionAttribute(value = "user") String user){
Map<String,Object> map=new HashMap<>();
map.put("session中的user",user);
return map;
}
到了这里,相信大家对于SpringMVC的前两个功能连接和获取参数已经有了一定程度的理解,后文将对于SpringMVC的最后一个功能输出数据的功能详细做介绍。