在我们前面的代码例子中, 都已经设置了响应数据Http响应结果可以是数据, 也可以是静态页面, 也可以针对响应设置状态码, Header信息等.
创建前端页面index.html(注意路径)
html代码如下:
Title Hello, Spring MVC,我是index页面.
后台代码如下:
@RestController public class IndexController { @RequestMapping("/index") public Object index() { //返回index.html return "/index.html"; } }
运行结果:
结果却发现, 页面未正确返回, http响应把"/index.html"当作http响应正文的数据. 那么Spring MVC如何才能识别出来index.html是一个静态页面, 并进行返回呢?
我们需要把@RestController 改为 @Controller.
正确代码如下:
@Controller public class IndexController { @RequestMapping("/index") public Object index() { //返回index.html return "/index.html"; } }
再次运行得到结果:
发现页面正确展示了.
我们之前讲过了MVC模式, 后端会返回视图, 这是早期时的概念
随着互联网的发展, 目前项目流行"前后端分离模式" , Java主要是用来做后端项目的开发, 所以就不再处理前端相关内容了.
MVC的概念也逐渐发生了变化, View不再返回视图, 而是返回显示视图时所需要的数据.
所以前面的@RestController其实是返回的数据, 是作为一个复合注解.
@RestController = @Controller(默认返回视图) + @ResponseBody(返回数据).
@Controller:定义一个控制器, Spring框架启动时加载, 把这个对象交给Spring管理.
@ResponseBody: 定义返回的数据为非视图, 返回一个text/html信息. 它既可以修饰类, 又可以修饰方法. (修饰类时:表示当前类的所有方法, 全部返回数据, 和@Controller可以合并为@RestController; 修饰方法时, 表示当前方法返回数据).
如果想返回视图的话, 只需要把@ResponseBody去掉就可以了, 也就是@Controller.
上面我们讲到, @ResponseBody表示返回数据.
@Controller @ResponseBody public class IndexController { @RequestMapping("/index") public Object index() { //返回index.html return "/index.html"; } }
加上@ResponseBody注解, 该方法就会把"/index.html"当作一个数据返回给前端.
@ResponseBody既是类注解, 又是方法注解
如果作用在类上, 表示该类的所有方法, 返回的就是数据, 如果作用在方法上, 表示该方法返回的就是数据.
当你在一个类中既想让一些方法返回视图, 又想让一些方法返回数据, 那么就可以给类加@Controller注解, 给想返回数据的方法加上@ResponseBody注解, 返回视图的方法不处理即可.
同样, 如果类上有@RestController注解时:表示所有方法上添加了@ResponseBody注解, 也就是当前类下所有方法返回值作为响应数据.
@Controller public class IndexController { @RequestMapping("/index") public Object index() { //返回index.html return "/index.html"; } @RequestMapping("/returnData") @ResponseBody public String returnData() { return "该方法返回数据"; } }
多个注解时, 没有先后顺序, 先写哪个都可以.
如果给第二个方法去掉@Responsebody, 程序就会报404错误.
因为程序会认为返回的应该是视图, 就会根据内容去查找文件, 但是文件查找不到, 路径不存在, 就报404.
后端返回数据的时候, 如果数据中有HTML代码, 也会被浏览器解析.
@RequestMapping("/returnHtml") @ResponseBody public String returnHtml() { return "hello HTML~
"; }
运行结果:
通过Fiddler观察结果, Content-Type为 text/html.
响应中的Content-Type常见取值有以下几种:
text/html:body数据格式是HTML
text/css:body数据格式是CSS
application/javascript:body数据格式是JavaScript
application/json:body数据格式是JSON.
Spring MVC也可以返回JSON
后端方法返回结果为对象.
@RequestMapping("/returnJson") @ResponseBody public HashMapreturnJson() { HashMap map = new HashMap<>(); map.put("Java", "Java value"); map.put("MySQL", "MySQL value"); map.put("Redis", "Redis value"); return map; }
运行结果:
通过Fiddler观察响应结果, Content-Type为application/json.
Spring MVC会根据我们方法的返回结果自动设置响应状态码, 程序员也可以手动指定状态码.
通过Spring MVC的内置对象HttpServletResponse提供的方法来进行设置.
@RequestMapping("/setStatus") @ResponseBody public String setStatus(HttpServletResponse response) { response.setStatus(418); return "设置状态码成功"; }
运行结果:
通过Fiddler观察设置的结果:
Http响应报头也会向客户端传递一些附加信息, 比如服务程序的名称, 请求的资源已移动到新地址等, 如:Content-Type, Local等.
这些信息通过@RequestMapping注解的属性来实现.
先来看@RequestMapping的源码:
@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping @Reflective({ControllerMappingReflectiveProcessor.class}) public @interface RequestMapping { String name() default ""; @AliasFor("path") String[] value() default {}; @AliasFor("value") String[] path() default {}; RequestMethod[] method() default {}; String[] params() default {}; String[] headers() default {}; String[] consumes() default {}; String[] produces() default {}; }
1.value:指定映射的URL.
2.method:指定请求的method类型, 如GET, POST等.
3.consumes:指定请求(request)的提交内容类型(Content-Type), 例:application/json, text/html;
4.produces:指定返回的内容类型, 仅当request请求头中的(Accept)类型中包含该指定类型才返回
5.Params: 指定request中必须包含某些参数值时, 才让该方法处理.
6.headers:指定request中必须包含某些指定的header值, 才能让该方法处理请求.
我们通过设置produces属性的值, 设置响应的报头Content-Type.
@RequestMapping(value = "/returnJson2", produces = "application/json") @ResponseBody public String returnJson2() { return "{\"sucess\":true}"; }
运行结果:
Fidder抓包结果:
如果不设置produces, 方法返回的结果为String时, Spring MVC默认返回类型, 是text/html.
设置其它Header的话, 需使用Spring MVC内置对象HttpServletResponse提供的方法来进行设置.
@RequestMapping("/setHeader") @ResponseBody public String setHeader(HttpServletResponse response) { response.setHeader("MyHeader", "MyHeaderValue"); return "设置Header成功"; }
void setHeader(String name, String value)设置一个带有给定的名称和值的Header. 如果name已经存在, 则覆盖旧的值.
运行成功后查看Fidder抓包结果: