一、SpringMVC简介1、什么是MVCMVC是一种软件架构模式(是一种软件架构设计思想,不止Java开发中用到,其它语言也需要用到),它将应用分为三块: M:Model(模型),负责业务处理及数据的收集V:View(视图),负责数据的展示C:Controller(控制器),负责调度。它是一个调度中心,它来决定什么时候调用Model来处理业务,什么时候调用View视图来展示数据 MVC架构模式的描述:前端浏览器发送请求给web服务器,web服务器中的Controller接收到用户的请求,Controller负责将前端提交的数据进行封装,然后Controller调用Model来处理业务,当Model处理完业务后会返回处理之后的数据给Controller,Controller再调用View来完成数据的展示,最终将结果响应给浏览器,浏览器进行渲染展示页面。
2、MVC架构模式与三层模型的区别 什么是三层模型
三层模型就是由Controller控制器和View视图组成的表现层,将Model数据模型拆封为业务层和与数据库交互的持久层image.png MVC架构模式与三层模型的区别?
MVC和三层模型都采用了分层结构来设计应用程序,都是降低耦合度,提高扩展力,提高组件复用性区别在于他们的关注点不同 三层模型更加关注业务逻辑组件的划分MVC架构模式关注的是整个应用程序的层次关系和分离思想现代的开发方式大部分都是MVC架构模式结合三层模型一起用3、什么是SpringMVCSpringMVC是一个实现了MVC架构模式的Web框架,底层基于Servlet实现SpringMVC已经将MVC架构模式实现了,因此只要我们是基于SpringMVC框架写代码Spring框架中有一个子项目叫做Spring Web,Spring Web子项目当中包含很多模块 Spring MVCSpring WebFluxSpring Web ServicesSpring Web FlowSpring WebSocketSpring Web Services ClientSpring架构图如下,其中Web中的servlet指的就是Spring MVC二、HelloWorld程序1、pom文件代码语言:javascript复制
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd" version="5.0">
接收客户端的HTTP请求:DispatcherServlet监听来自Web浏览器的HTTP请求,Tomcat已经将请求数据解析为Request对象处理请求的URL:DispatcherServlet将请求的URL与处理程序进行匹配,确定要调用哪个控制器(Controller)来处理此请求调用相应的控制器:DispatcherServlet将请求发送给找到的控制器处理,控制器将执行业务逻辑,然后返回一个模型对象(Model)渲染视图:DispatcherServlet将调用视图引擎,将模型对象呈现为用户可以查看的HTML页面返回响应给客户端:DispatcherServlet将为用户生成的响应发送回浏览器,响应可以包括表单、JSON、XML、HTML以及其它类型的数据4、html文件代码语言:javascript复制
hello world
5、执行Controller代码语言:javascript复制@Controller
public class HelloController {
@RequestMapping("/test")
public String test(){
return "success";
}
}配置Tomcat
启动tomcat,调用test
三、RequestMapping注解 @RequestMapping 注解是 Spring MVC 框架中的一个控制器映射注解,用于将请求映射到相应的处理方法上。具体来说,它可以将指定 URL 的请求绑定到一个特定的方法或类上,从而实现对请求的处理和响应。
RequestMapping的出现位置
通过源码可以看到RequestMapping注解只能出现在类上或者方法上当然类上和方法上也可以同时出现,类上是公共的,方法上是独有的1、value属性1.1、基础使用value属性是该注解最核心的属性,value属性填写的是请求路径,也就是说通过该请求路径与对应的控制器的方法绑定在一起value属性是一个字符串数组,表示可以提供多个路径,也就是说,多个不同的请求路径可以映射同一个控制器的同一个方法value属性和path属性互为别名,两个属性一样 举例
如下两个请求路径都可以正常访问到控制器的方法上 http://localhost:8080/springmvc/hello/test1http://localhost:8080/springmvc/hello/test2代码语言:javascript复制@Controller
@RequestMapping("/hello")
public class RequestMappingController {
@RequestMapping(value = {"/test1","test2"})
public String test(){
return "success";
}
}1.2、Ant风格(模糊匹配路径)value是可以用来匹配路径的,路径支持模糊匹配,我们把这种模糊匹配称之为Ant风格 ?:表示任意的单个字符*:表示任意的0个或多个字符**:表示任意的一层或多层目录(只能使用xxx/**的方式) 匹配?例子
代码语言:javascript复制@RequestMapping("/x?z/testValueAnt")
public String testValueAnt(){
return "success";
}匹配成功,可以正常访问到以上控制器的方法上匹配失败,抛错404 匹配*例子
代码语言:javascript复制@RequestMapping("/x*z/testValueAnt")
public String testValueAnt(){
return "success";
}匹配成功,可以正常访问到以上控制器的方法上在这里插入图片描述匹配失败,抛错404在这里插入图片描述 匹配**例子
spring6中**通配符只能出现在路径的末尾,否则抛错,spring5可以不用在末尾代码语言:javascript复制@RequestMapping("/testValueAnt/**")
public String testValueAnt(){
return "success";
}匹配成功,可以正常访问到以上控制器的方法上在这里插入图片描述1.3、路径占位符(@PathVariable)普通的请求路径:http://localhost:8080/springmvc/login?username=admin&password=123&age=20
restful风格的请求路径:http://localhost:8080/springmvc/login/admin/123/20
如果使用restful风格的请求路径,在控制器中应该如何获取请求中的数据呢?
不加@PathVariable路径变量注解会抛500异常代码语言:javascript复制@RequestMapping(value = "/testRestful/{id}/{username}/{age}")
public String testRestful(
@PathVariable("id") int id,
@PathVariable("username") String username,
@PathVariable("age") int age) {
System.out.println(id + "," + username + "," + age);
return "success";
}2、method属性2.1、基础使用如果前端发送请求的方式和后端的处理方式不一致时,会出现405错误HTTP状态码405,这种机制的作用是:限制客户端的请求方式,以保证服务器中数据的安全SpringMVC使用RequestMapping注解的method属性来实现限制请求方式在这里插入图片描述通过RequestMapping源码可以看到,method属性也是一个数组数组中的每个元素是RequestMethod,而RequestMethod是一个枚举类型的数据在这里插入图片描述 举例
只允许get和post请求方式,否则报错405代码语言:javascript复制@RequestMapping(value="/login", method = {RequestMethod.GET,RequestMethod.POST})
public String testMethod(){
return "success";
}2.2、衍生xxxMapping注解SpringMVC提供了另外一些注解,使用更加的方便 GetMapping:要求前端必须发送get请求PutMapping:要求前端必须发送put请求DeleteMapping:要求前端必须发送delete请求PatchMapping:要求前端必须发送patch请求 举例
两种方式效果一样,对比衍生注解更加简洁代码语言:javascript复制//@RequestMapping(value="/login", method = RequestMethod.POST)
@PostMapping("/login")
public String testMethod(){
return "success";
}2.3、web的请求方式 前端向服务器发送请求的方式包括哪些?共9种
GET:获取资源,只允许读取数据,不影响数据的状态和功能 使用URL中传递参数或者在HTTP请求的头部使用参数,服务器返回请求的资源POST:向服务器提交资源,可能还会改变数据的状态和功能 通过表单等方式提交请求体,服务器接收请求体后,进行数据处理PUT:更新资源,用于更新指定的资源上所有可编辑内容 通过请求体发送需要被更新的全部内容,服务器接收数据后,将被更新的资源进行替换或修改DELETE:删除资源,用于删除指定的资源 将要被删除的资源标识符放在URL中或请求体中HEAD:请求服务器返回资源的头部 与 GET 命令类似,但是所有返回的信息都是头部信息,不能包含数据体主要用于资源检测和缓存控制OPTIONS:请求获得服务器支持的请求方法类型,以及支持的请求头标志 OPTIONS则返回支持全部方法类型的服务器标志主要用于跨域检查PATCH:部分更改请求 当被请求的资源是可被更改的资源时,请求服务器对该资源进行部分更新,即每次更新一部分TRACE:服务器响应输出客户端的 HTTP 请求,主要用于调试和测试CONNECT:建立网络连接,通常用于加密 SSL/TLS 连接 ⚠️注意
使用超链接以及原生的form表单只能提交get和post请求put、delete、head请求可以使用发送ajax请求的方式来实现 GET和POST的区别
get请求比较适合从服务器端获取数据post请求比较适合向服务器端传送数据get请求支持缓存。 也就是说当第二次发送get请求时,会走浏览器上次的缓存结果,不再真正的请求服务器post请求不支持缓存。每一次发送post请求都会真正的走服务器3、params属性对于RequestMapping注解来说: value属性是一个数组,只要满足数组中的任意一个路径,就能映射成功method属性也是一个数组,只要满足数组中任意一个请求方式,就能映射成功params属性也是一个数组,不过要求请求参数必须和params数组中要求的所有参数完全一致后,才能映射成功在这里插入图片描述 params属性的4种用法
@RequestMapping(value="/login", params={"username", "password"}) 请求参数中必须包含username 和 password,才能与当前标注的方法进行映射@RequestMapping(value="/login", params={"!username", "password"}) 请求参数中不能包含username参数,但必须包含password参数,才能与当前标注的方法进行映射@RequestMapping(value="/login", params={"username=admin", "password"}) 请求参数中必须包含username参数,并且参数的值必须是admin,另外也必须包含password参数,才能与当前标注的方法进行映射@RequestMapping(value="/login", params={"username!=admin", "password"}) 请求参数中必须包含username参数,但参数的值不能是admin,另外也必须包含password参数,才能与当前标注的方法进行映射4、headers属性headers和params原理相同,用法也相同当前端提交的请求头信息和后端要求的请求头信息一致时,才能映射成功 headers属性的4种用法
@RequestMapping(value="/login", headers={"Referer", "Host"}) 请求头信息中必须包含Referer和Host,才能与当前标注的方法进行映射@RequestMapping(value="/login", headers={"!Referer", "Host"}) 请求头信息中不能包含Referer参数,但必须包含Host参数,才能与当前标注的方法进行映射@RequestMapping(value="/login", headers={"Referer=xxx", "Host"}) 请求头信息中必须包含Referer参数,并且参数的值必须是xxx,另外也必须包含Host参数,才能与当前标注的方法进行映射@RequestMapping(value="/login", headers={"Referer!=xxx", "Host"}) 请求头信息中必须包含Referer参数,但参数的值不能是xxx,另外也必须包含Host参数,才能与当前标注的方法进行映射四、获取请求参数1、原生Servlet API前端表单提交数据
在这里插入图片描述
F12查询提交数据方式
在这里插入图片描述后端控制器获取数据
代码语言:javascript复制@PostMapping(value="/register")
public String register(HttpServletRequest request){
// 通过当前请求对象获取提交的数据
String username = request.getParameter("username");
String password = request.getParameter("password");
String sex = request.getParameter("sex");
String[] hobbies = request.getParameterValues("hobby");
String intro = request.getParameter("intro");
System.out.println(username + "," + password +
"," + sex + "," + Arrays.toString(hobbies) + "," + intro);
return "success";
} 这样通过Servlet原生的API获取到提交的数据。但是这种方式不建议使用,因为方法的参数HttpServletRequest依赖Servlet原生API,Controller的测试将不能单独测试,必须依赖web服务器才能测试。
2、RequestParam注解2.1、value属性RequestParam注解作用:将请求参数与方法上的形参映射代码语言:javascript复制@PostMapping(value = "/register")
public String register(
@RequestParam(value = "username") String a,
@RequestParam(value = "password") String b,
@RequestParam(value = "sex") String c,
@RequestParam(value = "hobby") String[] d,
@RequestParam(name = "intro") String e
) {
System.out.println(a);
System.out.println(b);
System.out.println(c);
System.out.println(Arrays.toString(d));
System.out.println(e);
return "success";
}@RequestParam注解的两个属性value和name,互为别名,作用相同在这里插入图片描述发送请求时提交的数据是:name1=value1&name2=value2,则这个注解应该这样写:@RequestParam(value="name1")、@RequestParam(value="name2")2.2、required属性required属性用来设置该方法参数是否为必须的默认情况下,这个参数为 true,表示方法参数是必需的。如果请求中缺少对应的参数,则会抛出异常可以将其设置为false,false表示不是必须的,如果请求中缺少对应的参数,则方法的参数为null
在这里插入图片描述 举例
添加了一个 age 形参,没有指定 required 属性时,默认是true,表示必需的在这里插入图片描述但前端表单中没有年龄age,报错如下在这里插入图片描述2.2、defaultValue属性defaultValue属性用来设置形参的默认值当没有提供对应的请求参数或者请求参数的值是空字符串""的时候,方法的形参会采用默认值 举例
age属性设置为非必须,当前端不传值时候,默认年龄为18岁在这里插入图片描述3、根据形参名获取如果方法形参的名字和提交数据时的name相同,则@RequestParam可以省略代码语言:javascript复制@PostMapping(value="/register")
public String register(String username, String password, String sex,
String[] hobby, String intro){
System.out.println(username + "," + password + "," + sex + ","
+ Arrays.toString(hobby) + "," + intro);
return "success";
}4、根据实体类接收在SpringMVC中也可以使用POJO类/JavaBean实体类来接收请求参数不过有一个非常重要的要求:实体类的属性名必须和请求参数的参数名保持一致代码语言:javascript复制@PostMapping("/register")
public String register(User user){
System.out.println(user);
return "success";
}底层的实现原理:反射机制 先获取User对象实例,没有则反射实例化然后获取请求参数的名字,通过请求参数名字拼接出set属性名的方法名最后User实例和set属性方法反射给属性赋值请求参数是否可以赋值到JavaBean对应的属性上,不是取决于属性名,而是setter方法名5、RequestHeader注解该注解的作用是:将请求头信息映射到方法的形参上对于RequestHeader注解来说,也有三个属性:value、required、defaultValue,和RequestParam一样代码语言:javascript复制@PostMapping("/register")
public String register(User user,
@RequestHeader(value="Referer", required = false, defaultValue = "") String referer){
System.out.println(user);
System.out.println(referer);
return "success";
}6、CookieValue注解该注解的作用是:将请求提交的Cookie数据映射到方法的形参上对于CookieValue注解来说,也有三个属性:value、required、defaultValue,和RequestParam一样代码语言:javascript复制@GetMapping("/register")
public String register(User user,
@CookieValue(value="id", required = false, defaultValue = "110") String id){
System.out.println(user);
System.out.println(id);
return "success";
}7、请求的中文乱码问题7.1、get请求乱码get请求数据在URI后面提交,这个乱码问题怎么解决呢?解决办法是找到 CATALINA_HOME/config/server.xml文件,找到其中配置端口号的标签
源码解析在这里插入图片描述在这里插入图片描述五、Servlet的三个域对象请求域:request、会话域:session、应用域:application三个域都有以下三个方法:代码语言:javascript复制// 向域中存储数据
void setAttribute(String name, Object obj);
// 从域中读取数据
Object getAttribute(String name);
// 删除域中的数据
void removeAttribute(String name);主要是通过:setAttribute + getAttribute方法来完成在域中数据的传递和共享1、request域对象request对象代表了一次请求,一次请求一个request使用请求域的业务场景 在A资源中通过转发的方式跳转到B资源因为是转发,所以从A到B是一次请求如果想让A资源和B资源共享同一个数据,可以将数据存储到request域中在request域中共享数据有以下几种方式 使用原生Servlet API方式使用Model接口使用Map接口使用ModelMap类使用ModelAndView类 使用原生Servlet API方式
代码语言:javascript复制@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request){
// 向request域中存储数据
request.setAttribute("testRequestScope", "在SpringMVC中使用原生Servlet API实现request域数据共享");
return "view";
} 使用Model接口
代码语言:javascript复制@RequestMapping("/testModel")
public String testModel(Model model){
// 向request域中存储数据
model.addAttribute("testRequestScope", "在SpringMVC中使用Model接口实现request域数据共享");
return "view";
} 使用Map接口
代码语言:javascript复制@RequestMapping("/testMap")
public String testMap(Map
// 向request域中存储数据
map.put("testRequestScope", "在SpringMVC中使用Map接口实现request域数据共享");
return "view";
} 使用ModelMap类
代码语言:javascript复制@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
// 向request域中存储数据
modelMap.addAttribute("testRequestScope", "在SpringMVC中使用ModelMap实现request域数据共享");
return "view";
}Model、Map、ModelMap的关系?
输出打印Model、Map、ModelMap的Class,底层实例化的对象都是:BindingAwareModelMapBindingAwareModelMap的继承结构在这里插入图片描述BindingAwareModelMap继承ModelMap实现Model,而ModelMap又实现了Map接口在这里插入图片描述 使用ModelAndView类
为了更好的体现MVC架构模式,提供了一个类:ModelAndView。这个类的实例封装了Model和View也就是说这个类既封装业务处理之后的数据,也体现了跳转到哪个视图使用它也可以完成request域数据共享代码语言:javascript复制@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
// 创建“模型与视图对象”
ModelAndView modelAndView = new ModelAndView();
// 绑定数据
modelAndView.addObject("testRequestScope", "在SpringMVC中使用ModelAndView实现request域数据共享");
// 绑定视图
modelAndView.setViewName("view");
// 返回
return modelAndView;
}注意:
方法的返回值类型不是String,而是ModelAndView对象ModelAndView不是出现在方法的参数位置,而是在方法体中new的需要调用addObject向域中存储数据需要调用setViewName设置视图的名字 以上我们通过了五种方式完成了request域数据共享,这几种方式在底层DispatcherServlet调用我们的Controller之后,返回的对象都是ModelAndView。
在这里插入图片描述2、session域对象session对象代表了一次会话 从打开浏览器开始访问,到最终浏览器关闭,这是一次完整的会话每个会话session对象都对应一个JSESSIONID,而JSESSIONID生成后以cookie的方式存储在浏览器客户端浏览器关闭,JSESSIONID失效,会话结束使用会话域的业务场景 登录成功后保存用户的登录状态 使用原生Servlet API方式
代码语言:javascript复制@RequestMapping("/testSessionScope1")
public String testServletAPI(HttpSession session) {
// 向会话域中存储数据
session.setAttribute("testSessionScope1", "使用原生Servlet API实现session域共享数据");
return "view";
}3、application域对象application对象代表了整个web应用 服务器启动时创建,服务器关闭时销毁对于一个web应用来说,application对象只有一个使用应用域的业务场景 记录网站的在线人数 使用原生Servlet API方式
代码语言:javascript复制@RequestMapping("/testApplicationScope")
public String testApplicationScope(HttpServletRequest request){
// 获取ServletContext对象
ServletContext application = request.getServletContext();
// 向应用域中存储数据
application.setAttribute("applicationScope", "我是应用域当中的一条数据");
return "view";
}六、HttpMessageConverter消息转换器HttpMessageConverter是Spring MVC中非常重要的一个接口翻译为:HTTP消息转换器。该接口下提供了很多实现类,不同的实现类有不同的转换方式在这里插入图片描述转换器是HTTP协议与Java程序中的对象之间的互相转换在这里插入图片描述1、Form表单转换器和默认转换器 Form表单转换器
请求体中的数据是如何转换成user对象的,底层实际上使用了HttpMessageConverter接口的其中一个实现类FormHttpMessageConverter。
在这里插入图片描述 通过上图可以看出FormHttpMessageConverter是负责将请求协议转换为Java对象的。
默认转换器
Controller返回值看做逻辑视图名称,视图解析器将其转换成物理视图名称,生成视图对象,StringHttpMessageConverter负责将视图对象中的HTML字符串写入到HTTP协议的响应体中。最终完成响应。
在这里插入图片描述 通过上图可以看出StringHttpMessageConverter是负责将Java对象转换为响应协议的。
2、@ResponseBody首页面AJAX请求获取数据,非跳转页面Controller
2.1、Servlet原生API方式代码语言:javascript复制// 有返回值
@RequestMapping(value = "/hello1")
public String hello1(HttpServletResponse response) throws IOException {
response.getWriter().print("hello");
return null;
}
// 无返回值
@RequestMapping(value = "/hello2")
public void hello2(HttpServletResponse response) throws IOException {
response.getWriter().print("hello");
}页面展示
在这里插入图片描述注意:如果采用这种方式响应,则和 springmvc.xml 文件中配置的视图解析器没有关系,不走视图解析器了
2.2、@ResponseBody注解方式这里的"hello"不是逻辑视图名了,而是作为响应体的内容进行响应。直接输出到浏览器客户端程序中使用的消息转换器是:StringHttpMessageConverter,为什么会启用这个消息转换器呢? 因为你添加@ResponseBody这个注解代码语言:javascript复制@Controller
public class HelloController {
@RequestMapping(value = "/hello")
@ResponseBody
public String hello(){
// 由于你使用了 @ResponseBody 注解
// 以下的return语句返回的字符串则不再是“逻辑视图名”了
// 而是作为响应协议的响应体进行响应。
return "hello";
}
}通常AJAX请求需要服务器给返回一段JSON格式的字符串,可以返回JSON格式的字符串吗?当然可以,代码如下:代码语言:javascript复制@Controller
public class HelloController {
@RequestMapping(value = "/hello")
@ResponseBody
public String hello(){
return "{\"username\":\"zhangsan\",\"password\":\"1234\"}";
}
}页面展示
在这里插入图片描述此时底层使用的消息转换器还是:StringHttpMessageConverter那如果在程序中是一个POJO对象,怎么将POJO对象以JSON格式的字符串响应给浏览器呢? 方式一:自己写代码将POJO对象转换成JSON格式的字符串,用上面的方式直接return即可方式二:启用MappingJackson2HttpMessageConverter消息转换器2.3、MappingJackson2HttpMessageConverter(JSON转换器) 启动JSON消息转换器需要两个步骤
第一步:引入jackson依赖,可以将java对象转换为json格式字符串代码语言:javascript复制
第二步:开启注解驱动,会自动装配一个消息转换器:MappingJackson2HttpMessageConverter代码语言:javascript复制
代码语言:javascript复制@RequestMapping(value = "/hello")
@ResponseBody
public User hello(){
User user = new User("zhangsan", "18");
return user;
}将POJO对象转换成JSON格式的字符串,响应给前端在这里插入图片描述3、@RestController为了方便,Spring MVC中提供了一个注解@RestController。这一个注解代表了:@Controller + @ResponseBody@RestController标注在类上即可。被它标注的Controller中所有的方法上都会自动标注@ResponseBody代码语言:javascript复制@RestController
public class HelloController {
@RequestMapping(value = "/hello")
public User hello(){
User user = new User("zhangsan", "18");
return user;
}
}4、@RequestBody作用是直接将请求体传递给Java程序4.1、&拼接参数 在没有使用这个注解的时候:
代码语言:javascript复制@RequestMapping("/save")
public String save(User user){
// 执行保存的业务逻辑
userDao.save(user);
// 保存成功跳转到成功页面
return "success";
}当请求体提交的数据是:
代码语言:javascript复制username=zhangsan&password=1234&email=zhangsan@powernode.com那么Spring MVC会自动使用 FormHttpMessageConverter消息转换器,将请求体转换成user对象
当使用这个注解的时候:这个注解只能出现在方法的参数上
代码语言:javascript复制@RequestMapping("/save")
public String save(@RequestBody String requestBodyStr){
System.out.println("请求体:" + requestBodyStr);
return "success";
}Spring MVC仍然会使用 FormHttpMessageConverter消息转换器,将请求体直接以字符串形式传递给requestBodyStr变量
4.2、JSON格式参数如果请求体是JSON格式字符串,可以将其转化为POJO对象此时必须使用@RequestBody注解来完成底层使用的消息转换器是:MappingJackson2HttpMessageConverter启动步骤与@ResponseBody一样,引入jackson依赖、开启注解驱动代码语言:javascript复制@RequestMapping("/send")
@ResponseBody
public String send(@RequestBody User user){
System.out.println(user);
System.out.println(user.getUsername());
System.out.println(user.getPassword());
return "success";
}5、RequestEntity这个类的实例封装了整个请求协议:包括请求行、请求头、请求体所有信息代码语言:javascript复制@RequestMapping("/send")
@ResponseBody
public String send(RequestEntity
System.out.println("请求方式:" + requestEntity.getMethod());
System.out.println("请求URL:" + requestEntity.getUrl());
HttpHeaders headers = requestEntity.getHeaders();
System.out.println("请求的内容类型:" + headers.getContentType());
System.out.println("请求头:" + headers);
User user = requestEntity.getBody();
System.out.println(user);
System.out.println(user.getUsername());
System.out.println(user.getPassword());
return "success";
}执行结果:
在这里插入图片描述6、ResponseEntity提供对HTTP响应的全方位控制,包括设置状态码、响应头和响应体默认只返回body的内容作为响应体,不是完整的ResponseEntity对象(包括状态码和头部)6.1、返回字符串如果ResponseEntity的body是字符串,则响应内容是纯文本代码语言:javascript复制@GetMapping("/string-response")
public ResponseEntity
return ResponseEntity.ok("Hello, World!");
}结果
代码语言:javascript复制Hello, World!HTTP 状态码:200 OKContent-Type:text/plain6.2、返回JSON对象如果返回的是对象(如Map或自定义对象),Spring会自动将其序列化为JSON代码语言:javascript复制@GetMapping("/json-response")
public ResponseEntity
Map
response.put("message", "Hello, World!");
response.put("status", 200);
return ResponseEntity.ok(response);
}
@GetMapping("/custom-response")
public ResponseEntity
CustomResponse response = new CustomResponse("Hello, World!", 200);
return ResponseEntity.ok(response);
}
public class CustomResponse {
private String message;
private int status;
// 省略get、set和构造方法
}结果
代码语言:javascript复制{
"message": "Hello, World!",
"status": 200
}HTTP 状态码:200 OKContent-Type:application/json6.3、返回带有HTTP头的响应可以通过设置HttpHeaders来返回带有自定义头的响应代码语言:javascript复制@GetMapping("/header-response")
public ResponseEntity
HttpHeaders headers = new HttpHeaders();
headers.add("Custom-Header", "CustomValue");
return ResponseEntity.ok()
.headers(headers)
.body("Response with custom header");
}结果
代码语言:javascript复制Response with custom headerHTTP 状态码:200 OK
Headers:
代码语言:javascript复制Custom-Header: CustomValue
Content-Type: text/plain6.4、返回错误状态码可以通过ResponseEntity返回指定的错误状态码以及相关错误信息代码语言:javascript复制@GetMapping("/error-response")
public ResponseEntity
// return ResponseEntity.status(404).body("Resource not found"); - 自定义错误码
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Resource not found");
}结果
代码语言:javascript复制Resource not foundHTTP 状态码:404 Not FoundContent-Type:text/plain6.5、构建标准化API响应在实际开发中会统一返回一种结构化的响应格式,比如包含data、message和status的JSON代码语言:javascript复制@GetMapping("/standard-response")
public ResponseEntity
StandardResponse response = new StandardResponse(
HttpStatus.OK.value(), "Success", Map.of("key", "value")
);
return ResponseEntity.ok(response);
}
public class StandardResponse {
private int status;
private String message;
private Object data;
// 省略get、set和构造方法
}结果
代码语言:javascript复制{
"status": 200,
"message": "Success",
"data": {
"key": "value"
}
}七、异常处理器1、默认异常处理器方法执行过程中出现了异常,跳转到对应的视图,在视图上展示友好信息默认处理器DefaultHandlerExceptionResolver核心方法:
在这里插入图片描述当请求方式和处理方式不同时,DefaultHandlerExceptionResolver的默认处理态度是:
在这里插入图片描述2、自定义异常处理器2.1、跳转错误页面代码语言:javascript复制@ControllerAdvice
public class ExceptionController {
@ExceptionHandler
public String exceptionHandler(Exception e, Model model){
model.addAttribute("e", e);
return "error";
}
}代码语言:javascript复制
出错了,请联系管理员!
2.2、返回错误响应对象代码语言:javascript复制@ControllerAdvice
public class ExceptionController {
@ExceptionHandler(value = {Exception.class})
@ResponseBody
public ResponseEntity
// 这里先判断拦截到的Exceptiion是不是我们自定义的异常类型
if (e instanceof MyException) {
MyException myException = (MyException) e;
return ResponseEntity.status(500).body(myException.getMeg());
} else {
// 如果拦截的异常不是我们自定义的异常(例如:数据库主键冲突)
return ResponseEntity.status(500).body("服务器端异常");
}
}
}八、拦截器1、拦截器概述拦截器作用是在请求到达控制器之前或之后进行拦截,可以对请求和响应进行一些特定的处理拦截器可以用于很多场景下 登录验证:对于需要登录才能访问的网址,使用拦截器可以判断用户是否已登录,如果未登录则跳转到登录页面权限校验:根据用户权限对部分网址进行访问控制,拒绝未经授权的用户访问请求日志:记录请求信息,例如请求地址、请求参数、请求时间等,用于排查问题和性能优化更改响应:可以对响应的内容进行修改,例如添加头信息、调整响应内容格式等2、拦截器和过滤器的区别过滤器更注重在请求和响应的流程中进行处理,可以修改请求和响应的内容,例如设置编码和字符集、请求头、状态码等拦截器则更加侧重于对控制器进行前置或后置处理,在请求到达控制器之前或之后进行特定的操作,例如打印日志、权限验证等Filter、Servlet、Interceptor、Controller的执行顺序:
3、拦截器的创建与基本配置 定义拦截器
实现org.springframework.web.servlet.HandlerInterceptor 接口,共有三个方法可以进行选择性的实现 preHandle:处理器方法调用之前执行(返回true放行,false拦截)postHandle:处理器方法调用之后执行afterCompletion:渲染完成后执行(无论是否抛异常最终必会执行)代码语言:javascript复制@Component
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("处理器方法前调用");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("处理器方法后调用");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("渲染完成后调用");
}
} 基本配置
springmvc.xml配置如下
代码语言:javascript复制
添加组件扫描
注意:对于这种基本配置来说,拦截器是拦截所有请求的
4、多个拦截器执行顺序 如果所有拦截器preHandle都返回true
按照springmvc.xml文件中配置的顺序,自上而下调用 preHandle
代码语言:javascript复制
执行顺序:
如果其中一个拦截器preHandle返回false
代码语言:javascript复制
如果interceptor2的preHandle返回false,执行顺序:
规则:只要有一个拦截器preHandle返回false,所有postHandle都不执行。但返回false的拦截器的前面的拦截器按照逆序执行afterCompletion。