找往期文章包括但不限于本期文章中不懂的知识点:
个人主页: 我要学编程程(ಥ_ಥ)-CSDN博客
所属专栏: JavaEE
初始JavaEE篇 ------ Spring Web MVC入门(上)
在上篇文章中,我们学习了一些注解的使用、Postman模拟前端传递数据的使用以及如何在后端接受并处理前端的数据。接下来我们就需要学习响应的返回,将前端的数据处理完成之后,就需要返回数据给前端。
目录
返回响应数据
Http请求的响应结果可以是数据,也可以是静态页面,也可以针对响应设置状态码、Header信息等。
返回静态页面
返回静态页面需要学习一个新的注解:@Controller,这个注解与@RestController 有所不同。@RestController 表示该控制器的所有方法都会默认返回 JSON 或其他对象,而不是解析和返回视图页面。而@Controller 就是按照页面来解析的。
前端代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
后端代码:
java
@RequestMapping("/Response")
@Controller
public class ResponseController {
// 返回静态页面
@RequestMapping("/index")
public String index() {
return "/index.html";
}
}
这里的 "/" 代指的是 src/main/resource/static 目录下。可能会存在多个目录,那时就需要将完整路径显示出来。
访问的结果:
![](https://i-blog.csdnimg.cn/direct/be0cbdbe524049abb4038c830be729eb.png)
但如果我们使用@RestController注解的话,就只会返回一个字符串。这就是两者在返回数据时,会通过注解的不同,从而返回不同的资源。@Controller注解只会返回视图,而@ResponseBody注解会返回JSON数据或对象。
注意:
1、前端代码在Spring项目中,是存放在 src/main/resource/static 目录下的。
![](https://i-blog.csdnimg.cn/direct/054711576b884ea1ac85a008aa7d8bfd.png)
2、@RestController = @Controller + @ResponseBody,也就是说@RestCont注解是两者的结合体,我们也可以通过@RestController的源码来观察:
![](https://i-blog.csdnimg.cn/direct/b84941fcd3374d4aa65772eb248a0b9b.png)
注解应用类是一个枚举类,源代码如下(了解即可):
java
public enum ElementType {
/** Class, interface (including annotation interface), enum, or record
* declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation interface declaration (Formerly known as an annotation type.) */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE,
/**
* Module declaration.
*
* @since 9
*/
MODULE,
/**
* Record component
*
* @jls 8.10.3 Record Members
* @jls 9.7.4 Where Annotations May Appear
*
* @since 16
*/
RECORD_COMPONENT;
}
注解的生命周期有三个阶段:源码、字节码(编译)、运行。
java
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE, // 只存在于源码阶段
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS, // 既存在于源码,也存在于字节码(编译)阶段
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME // 既存在于源码阶段,也存在于字节码阶段,还存在与运行时
}
返回普通数据
我们前面学习请求时,返回的响应都是字符串数据,使用的注解是@RestController,这里就包含了@ResponseBody 注解,因而可以返回数据。
如果我们现在在之前的代码的基础上,加上一个返回字符串数据的代码会成功返回吗?
java
@RequestMapping("/login")
public String login(String userName, String password) {
return "服务器异常,请稍后重试~";
}
![](https://i-blog.csdnimg.cn/direct/c3633226f2114b50afcd0c0c94c855e3.png)
我们会发现,根本访问不了, 直接告诉我们资源不存在。因为这里的注解是@Controller说明是需要返回的是视图,那么Spring就会去扫描视图,但是最终却不存在这个视图,即404。
解决方法是在原本的方法前面加上@ResponseBody注解,这样最终就是@RestController注解了。
java
@ResponseBody
@RequestMapping("/login")
public String login(String userName, String password) {
return "服务器异常,请稍后重试~";
}
![](https://i-blog.csdnimg.cn/direct/2bbbd51bff8649fb8ae8a41045b00b70.png)
@ResponseBody既是类注解,又是方法注解。如果作用在类上,表示该类的所有方法,返回的都是数据,如果作用在方法上,表示该方法返回的是数据。
返回HTML代码片段
后端的代码中,如果带有HTML代码片段就会被浏览器解析出来,但我们不想要浏览器解析,该怎么做呢?
java
@ResponseBody
@RequestMapping("/returnHtml")
public String returnHtml() {
return "<h1>Hello World</h1>";
}
上述代码在浏览器中访问就会被解析成下面这样:
![](https://i-blog.csdnimg.cn/direct/ed84af607fbe4db89a9d0c624864a3ad.png)
之所以将HTML标签解析成具体可视化页面,是因为响应数据的返回格式是:text/html,所以浏览器就会解析HTML标签。那如果我们将返回数据返回设置成其他的数据是否就可以让浏览器不再按照HTML标签来解析呢?我们可以使用fiddler对Http请求进行抓包处理。下图是修改之前的结果:
![](https://i-blog.csdnimg.cn/direct/704c38c6c80344acbc568058d6ca5534.png)
修改之后的结果:
代码:
java
@ResponseBody
// produces-设置方法返回的数据类型或内容类型
@RequestMapping(value = "/returnHtml",produces = "text/plain")
public String returnHtml(HttpServletResponse response) {
return "<h1>Hello World</h1>";
}
![](https://i-blog.csdnimg.cn/direct/19f206b481c744b0aa549e99a7492a02.png)
浏览器的结果:
![](https://i-blog.csdnimg.cn/direct/83743dda977d4df39dfcfddf99f3a99c.png)
我们想要设置成什么类型,可以直接在搜索引擎上去找或者问AI即可。
返回JSON数据
我们前面已经学习了,后端在传输对象时,都是Spring框架使用Jackson将对象序列化为JSON数据从而进行传输。
java
@ResponseBody
@RequestMapping("/returnJSON")
public UserInfo returnJSON() {
return new UserInfo();
}
![](https://i-blog.csdnimg.cn/direct/ebe359a8548b429aa52019cb34792c68.png)
设置状态码
SpringMVC会根据我们方法的返回结果自动设置响应状态码,程序员也可以手动指定状态码。通过SpringMVC的内置对象HttpServletResponse提供的方法来进行设置。
java
@ResponseBody
@RequestMapping("/setStatus")
public String setStatus(HttpServletResponse response) {
response.setStatus(500);
return "服务器一切正常,但是就是返回500!嘿嘿~";
}
![](https://i-blog.csdnimg.cn/direct/35978dd0245748fe9a0b90912b125f16.png)
虽然状态码被设置成了非正常的情况,但是响应依旧是正常的,即状态码不会影响正常响应结果。
设置Header
Http响应报头也会向客户端传递一些附加信息,比如:服务程序的名称,请求的资源,已移动到新地址等,如:Content-Type等信息。这些信息通过 @RequestMapping 注解的属性来实现。即设置Header信息都是通过@RequestMapping注解的属性来实现的。
先来看@RequestMapping的源码:
java
@Target({ElementType.TYPE, ElementType.METHOD}) // 类注解、方法注解
@Retention(RetentionPolicy.RUNTIME) // 源码、字节码、运行阶段皆存在
@Documented
@Mapping
@Reflective(ControllerMappingReflectiveProcessor.class)
public @interface RequestMapping {
// 用来指定映射的名称(例如,"/r1"等)
String name() default "";
// value 和 path 都是指定映射的URL
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
// 指定请求的类型
RequestMethod[] method() default {};
// 指定请求中必须包含某些参数值(只有包含时,才处理)
String[] params() default {};
// 用来指定请求中的头部信息(只有包含指定信息时,才处理)
String[] headers() default {};
// 用来指定请求的 Content-Type
String[] consumes() default {};
// 用来指定方法返回的 Content-Type
String[] produces() default {};
}
注意:name 和 value 区别:
java
@RequestMapping(name = "myMapping", value = "/api/user")
public String getUser() {
return "user";
}
上述代码中,name用作映射的标识符,通常用于生成文档、日志或调试。value是实际请求的URL。在开发中,我们一般不会去使用name属性。
通过设置 produces 属性的值,来设置相应的报头Content-Type:
java
@ResponseBody
@RequestMapping(value = "/setContentType",produces = "application/json")
public String setContentType() {
return "{\"name\": \"zhangsan\"}";
}
上述代码是将响应报头的Content-Type设置成JSON数据,这样最终返回的响应数据就会按照与之对应的数据来解析。
![](https://i-blog.csdnimg.cn/direct/068824c77be14c33ba4dde44fcb5086d.png)
注意:在Java中," 是属于 特殊字符,所以需要使用反斜杠(\
)进行转义。正常的JSON数据是下面这样的:
{"name": "zhangsan"}
经过转义之后的结果就是下面这样(在 " 前面加上 \ 即可):
{\"name\": \"zhangsan\"}
除了可以设置原本的属性之外,还可以手动添加新的属性到Header中:
java
@ResponseBody
@RequestMapping("setHeader")
public String setHeader(HttpServletResponse response) {
response.setHeader("name", "zhangsan");
return "header设置成功";
}
![](https://i-blog.csdnimg.cn/direct/df9b862717ad42029d510059a93fc7ba.png)
好啦!本期 初始JavaEE篇 ------ Spring Web MVC入门(下)的学习之旅 就到此结束啦!我们下一期再一起学习吧!