官方链接
核心功能:用于拦截和处理客户端的请求

基本使用

新建一个Maven web项目,添加依赖

  1. <!-- JavaEE基本依赖-->
  2. <dependency>
  3. <groupId>javax.servlet</groupId>
  4. <artifactId>javax.servlet-api</artifactId>
  5. <version>4.0.1</version>
  6. <scope>provided</scope>
  7. </dependency>
  8. <dependency>
  9. <groupId>javax.servlet</groupId>
  10. <artifactId>jsp-api</artifactId>
  11. <version>2.0</version>
  12. <scope>provided</scope>
  13. </dependency>
  14. <!-- SpringMVC -->
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-webmvc</artifactId>
  18. <version>5.2.8.RELEASE</version>
  19. </dependency>
  20. <!-- 日志 -->
  21. <dependency>
  22. <groupId>ch.qos.logback</groupId>
  23. <artifactId>logback-classic</artifactId>
  24. <version>1.2.3</version>
  25. </dependency>
  26. <!-- 单元测试 -->
  27. <dependency>
  28. <groupId>junit</groupId>
  29. <artifactId>junit</artifactId>
  30. <version>4.13</version>
  31. <scope>test</scope>
  32. </dependency>

Spring-webmvc会依赖其他库
image.png
在以前我们需要自己创建Servlet,并且每一个请求都对应一个Servlet。这样就比较麻烦。
我们想在使用SpringMVC提供的Servlet。

  • 首先在web.xml进行配置 ```xml <?xml version=”1.0” encoding=”UTF-8”?>
  1. <servlet>
  2. <servlet-name>springmvc</servlet-name>
  3. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  1. <init-param>
  2. <param-name>contextConfigLocation</param-name>
  3. <param-value>classpath:applicationContext.xml</param-value>
  4. </init-param>
  5. <!-- 项目部署到服务器,就会创建Servlet,大于等于0就会部署到服务器就创建,值越小越先创建 -->
  6. <load-on-startup>0</load-on-startup>
  7. </servlet>
  8. <servlet-mapping>
  9. <servlet-name>springmvc</servlet-name>
  1. <url-pattern>/</url-pattern>
  2. </servlet-mapping>

  1. - 创建controller控制器类,处理客户端请求
  2. ```java
  3. @Controller //需要被扫描到,所以可以使用Spring配置文件扫描到该控制器
  4. public class UserController {
  5. @RequestMapping("/login")
  6. @ResponseBody
  7. public String Login(){
  8. System.out.println("拦截到了/login请求");
  9. return "/login";
  10. }
  11. }

在Spring配置文件applicationContext.xml,配置上面的类要被扫描到

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:context="http://www.springframework.org/schema/context"
  5. 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 http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
  6. <!-- 保证@Controller能够使用扫描到 -->
  7. <context:component-scan base-package="com.lff"/>
  8. </beans>

image.png
请求过程

Spring MVC - 图3

@RequestMapping

可以用在类或者方法上

  1. @Controller
  2. @RequestMapping("/user")
  3. public class UserController {
  4. @RequestMapping("/login")
  5. @ResponseBody
  6. public String login(){
  7. System.out.println("拦截到了/login请求");
  8. return "/login";
  9. }
  10. @RequestMapping("/remove")
  11. @ResponseBody
  12. public String remove(){
  13. System.out.println("拦截到了/user/remove请求");
  14. return "/user/remove";
  15. }
  16. @RequestMapping("/get")
  17. @ResponseBody
  18. public String get(){
  19. System.out.println("拦截到了/user/get请求");
  20. return "/user/get";
  21. }
  22. }

image.png

设置请求方式

设置Post请求

  • 可以使用@RequestMapping

    1. @RequestMapping(value = "/remove",method = RequestMethod.POST)
  • 也可以使用@PostMapping,这种方式是上面的语法糖格式

    1. @PostMapping("/remove")

    使用@RequestMapping(value = “/remove”)这种方式如果不写method默认post和get都可以

    设置Get请求

  • @RequestMapping

    1. @RequestMapping(value = "/login",method = RequestMethod.GET)
  • @GetMapping(“/get”)

示例代码

  1. package com.lff;
  2. import org.springframework.stereotype.Controller;
  3. import org.springframework.web.bind.annotation.*;
  4. @Controller
  5. @RequestMapping("/user")
  6. public class UserController {
  7. @RequestMapping(value = "/login",method = RequestMethod.GET)
  8. @ResponseBody
  9. public String login(){
  10. System.out.println("拦截到了/login请求");
  11. return "/login";
  12. }
  13. @RequestMapping(value = "/remove",method = RequestMethod.POST)
  14. @ResponseBody
  15. public String remove(){
  16. System.out.println("拦截到了/user/remove请求");
  17. return "/user/remove";
  18. }
  19. @GetMapping("/get")
  20. @ResponseBody
  21. public String get(){
  22. System.out.println("拦截到了/user/get请求");
  23. return "/user/get";
  24. }
  25. @PostMapping("/removeList")
  26. @ResponseBody
  27. public String removeList(){
  28. System.out.println("拦截到了/user/removeList请求");
  29. return "/user/removeList";
  30. }
  31. }

请求参数

Spring MVC会给请求方法里面传递很多参数,比如HttpServletRequest、HttpServletResponse、WebRequest等

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(HttpServletRequest request, WebRequest webRequest, HttpServletResponse response, HttpSession session){
  4. System.out.println("拦截到了/login请求");
  5. return "/login";
  6. }

具体的详细参数信息可以参考官方文档。

示例
新建index.jsp文件

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. 欢迎注册,请输入用户名
  8. <form method="POST" action="login">
  9. <p>姓名:<input type="text" name="name"></input></p>
  10. <p>年龄:<input type="text" name="age"></input></p>
  11. <p>密码:<input type="password" name="password"></input></p>
  12. <p><input type="submit" value="确定"></input></p>
  13. </form>
  14. </body>
  15. </html>

对应的处理方法,可以直接接受上面的参数

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(String name,String age,String password){
  4. System.out.println("name = " + name);
  5. System.out.println("age = " + age);
  6. System.out.println("password = " + password);
  7. return "/login";
  8. }

请求方法的参数名和请求过来的参数名称一样就可以了。默认如果客户端没有传,则为null。

有时如果想某一个参数必须传,可以在参数名称前加@RequestParam

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(@RequestParam String name,String age,String password,@RequestParam String address){
  4. System.out.println("name = " + name);
  5. System.out.println("age = " + age);
  6. System.out.println("password = " + password);
  7. return "/login";
  8. }

如果客户端没有传参数会报错

image.png
也可在@RequestParam里面指定客户端传来的名称,以及是否为必传参数
如在JSP里面有一个标签name改成my_name

  1. <p>姓名:<input type="text" name="my_name"></input></p>

服务端接收参数时

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(@RequestParam(value = "my_name",required = false) String name,String age,String password){
  4. System.out.println("name = " + name);
  5. System.out.println("age = " + age);
  6. System.out.println("password = " + password);
  7. return "/login";
  8. }

如果请求参数很多使用上面的方式接收参数就很麻烦,我们可以使用模型接收,只需要模型里面的属性名与传递的参数名称保持一致就可以了
比如提交表单的参数如下

  1. <form method="POST" action="login">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p>密码:<input type="password" name="password"></input></p>
  5. <p><input type="submit" value="确定"></input></p>
  6. </form>

新建模型类

  1. public class Person {
  2. private String name;
  3. private Integer age;
  4. private String password;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public Integer getAge() {
  12. return age;
  13. }
  14. public void setAge(Integer age) {
  15. this.age = age;
  16. }
  17. public String getPassword() {
  18. return password;
  19. }
  20. public void setPassword(String password) {
  21. this.password = password;
  22. }
  23. }

服务端接收参数

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(Person person){
  4. System.out.println("name = " + person.getName());
  5. System.out.println("age = " + person.getAge());
  6. System.out.println("password = " + person.getPassword());
  7. return "/login";
  8. }

直接传对应的模型对象就可以了

PathVariable

如果路径里面有可变参数,比如根据id获取哪一个人,请求参数可能是这样的/get/1、/get/2、/get/3……
我们怎么获取后面的变量参数呢?
可以先定义变量名称:格式{id}
获取时通过@PathVariable 变量获取
示例

  1. @GetMapping("/get/{id1}")
  2. @ResponseBody
  3. public String getPerson(@PathVariable("id1") Integer id){
  4. System.out.println("id = " + id);
  5. return "getPerson id = " + id;
  6. }

image.png

接收map类型的参数

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(Map<String,Object> map){
  4. System.out.println("map = " + map);
  5. return "/login";
  6. }

默认情况下是不能直接接收map类型参数的,需要参数前面加@RequestParam

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(@RequestParam Map<String,Object> map){
  4. System.out.println("map = " + map);
  5. return "/login";
  6. }

如果有相同的参数名呢?

  1. <form method="POST" action="login">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p>密码:<input type="password" name="password"></input></p>
  5. <p>篮球:<input type="checkbox" name="hobby"></input></p>
  6. <p>足球:<input type="checkbox" name="hobby"></input></p>
  7. <p>台球:<input type="checkbox" name="hobby"></input></p>
  8. <p><input type="submit" value="确定"></input></p>
  9. </form>

比如上面的爱好有很多个,由于服务端使用map接收的,key是唯一的,我们可以使用下面的数组方式接收hobby

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(@RequestParam Map<String,Object> map,String[] hobby){
  4. System.out.println("map = " + map);
  5. for (String value: hobby
  6. ) {
  7. System.out.println(value);
  8. }
  9. return "/login";
  10. }

上面是使用数组的方式接收,也可以使用List接收

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(@RequestParam Map<String,Object> map,@RequestParam List<String> hobby){
  4. System.out.println("map = " + map);
  5. for (String value: hobby
  6. ) {
  7. System.out.println(value);
  8. }
  9. return "/login";
  10. }

使用List要加@RequestParam 否则会如下错误

  1. nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface java.util.List

Multipart参数

如果客户端使用的是multipart/form-data的方式上传参数,服务端怎么接收参数?

  1. <form method="POST" action="login" enctype="multipart/form-data">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p><input type="submit" value="确定"></input></p>
  5. </form>

因为multipart/form-data上传的参数在发送HTTP请求时会有分割线,需要手动去解析该类型的参数。我们使用第三方库解析

  1. Maven依赖

    1. <!-- 解析Multipart类型参数 -->
    2. <dependency>
    3. <groupId>commons-fileupload</groupId>
    4. <artifactId>commons-fileupload</artifactId>
    5. <version>1.4</version>
    6. </dependency>
  2. CommonsMultipartResolver 添加到IOC容器里面,id值固定为multipartResolver

    1. <!-- 解析Multipart参数 -->
    2. <bean id="multipartResolver"
    3. class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    4. <!-- 设置编码-->
    5. <property name="defaultEncoding" value="UTF-8"/>
    6. <!-- 限制每个文件上传大小-->
    7. <property name="maxUploadSizePerFile" value="20480" />
    8. <!-- 限制总的上传大小,以字节为单位,默认-1表示无限制-->
    9. <property name="maxUploadSize" value="20480" />
    10. </bean>

    服务端直接处理即可

    1. @PostMapping("/login")
    2. @ResponseBody
    3. public String login(String name,Integer age){
    4. System.out.println("name = " + name);
    5. System.out.println("age = " + age);
    6. return "/login";
    7. }

文件参数

如果客户端传的是文件参数,服务端该如何能接受到?

  1. <form method="POST" action="login" enctype="multipart/form-data">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p>文件:<input type="file" name="headerImg1"></input></p>
  5. <p><input type="submit" value="确定"></input></p>
  6. </form>

在上面Multipart参数配置的基础上,服务端使用MultipartFile类型的参数接受

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(String name, Integer age, MultipartFile headerImg1,HttpServletRequest request) throws IOException {
  4. System.out.println("name = " + name);
  5. System.out.println("age = " + age);
  6. String fileName = headerImg1.getOriginalFilename();
  7. String path = request.getServletContext().getRealPath("/upload/img/" +fileName);
  8. System.out.println("path = " + path);
  9. File file = new File(path);
  10. //把上传的文件写到硬盘上
  11. headerImg1.transferTo(file);
  12. return "/login";
  13. }

多个文件上传

  1. <form method="POST" action="login" enctype="multipart/form-data">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p>文件1:<input type="file" name="headerImg1"></input></p>
  5. <p>文件2:<input type="file" name="headerImg2"></input></p>
  6. <p><input type="submit" value="确定"></input></p>
  7. </form>

服务端处理,只需多添加一个参数即可

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(String name, Integer age, MultipartFile headerImg1,MultipartFile headerImg2,HttpServletRequest request) throws IOException {
  4. System.out.println("name = " + name);
  5. System.out.println("age = " + age);
  6. String fileName1 = headerImg1.getOriginalFilename();
  7. String fileName2 = headerImg2.getOriginalFilename();
  8. String path1 = request.getServletContext().getRealPath("/upload/img/" +fileName1);
  9. String path2 = request.getServletContext().getRealPath("/upload/img/" +fileName2);
  10. File file = new File(path1);
  11. //把上传的文件写到硬盘上
  12. headerImg1.transferTo(file);
  13. file = new File(path2);
  14. headerImg2.transferTo(file);
  15. return "/login";
  16. }

也有可能客户端使用相同的名称传递多个文件参数

  1. <form method="POST" action="login" enctype="multipart/form-data">
  2. <p>姓名:<input type="text" name="name"></input></p>
  3. <p>年龄:<input type="text" name="age"></input></p>
  4. <p>文件1:<input type="file" name="headerImg"></input></p>
  5. <p>文件2:<input type="file" name="headerImg"></input></p>
  6. <p><input type="submit" value="确定"></input></p>
  7. </form>

服务端可以使用数组接受

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(String name, Integer age, MultipartFile[] headerImg,HttpServletRequest request) throws IOException {
  4. for (MultipartFile file: headerImg
  5. ) {
  6. System.out.println(file.getOriginalFilename());
  7. }
  8. return "/login";
  9. }

Post请求乱码问题

当客户端发送post请求有中文字符时,会出现乱码问题。我们可以做如下处理

  1. request.setCharacterEncoding("UTF-8");

但是每一个请求方法里面都设置就不高级。我们可以自定义过滤器处理。springMVC已经考虑了这个问题,可以使用springMVC自带的过滤器进行处理。在web.xml中配置如下信息

  1. <!-- 使用springMVC自带的过滤器处理post请求乱码问题-->
  2. <filter>
  3. <filter-name>characterEncodingFilter</filter-name>
  4. <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  5. <init-param>
  6. <param-name>encoding</param-name>
  7. <param-value>UTF-8</param-value>
  8. </init-param>
  9. </filter>
  10. <filter-mapping>
  11. <filter-name>characterEncodingFilter</filter-name>
  12. <url-pattern>/*</url-pattern>
  13. </filter-mapping>

上面解决了客户端发送请求到达服务端乱码的问题。

服务端响应给客户端后也可能乱码,比如下面

  1. @PostMapping("/login")
  2. @ResponseBody
  3. public String login(Person person){
  4. System.out.println("name = " + person.getName());
  5. System.out.println("age = " + person.getAge());
  6. System.out.println("password = " + person.getPassword());
  7. return "/login 哈哈哈哈";
  8. }

返回客户端是“/login 哈哈哈哈”

image.png
以前我们是这样处理响应到客户端乱码问题的

  1. response.setContentType("text/plain; charset=UTF-8");

在Shpring中处理乱码有很多种方案。
第一种方式

  1. @PostMapping(value = "/login",produces = "text/plain; charset=UTF-8")

第二种方式
在applicationContext.xml文件里面配置如下信息

  1. <mvc:annotation-driven>
  2. <mvc:message-converters>
  3. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  4. <property name="defaultCharset" value="UTF-8" />
  5. </bean>
  6. </mvc:message-converters>
  7. </mvc:annotation-driven>

注意annotation-driven标签的所在的位置,以mvc结尾的。
Snipaste_2021-11-18_22-25-33.png

DispatcherServlet中的URL匹配问题

我们在web.xml配置的url匹配模式如下

  1. <!-- 使用SpringMVC提供的DispatcherServlet进行处理拦截客户端的请求-->
  2. <servlet>
  3. <servlet-name>springmvc</servlet-name>
  4. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  5. <!-- 加载Spring的配置文件,配置文件里面配置要扫描的类等-->
  6. <init-param>
  7. <param-name>contextConfigLocation</param-name>
  8. <param-value>classpath:applicationContext.xml</param-value>
  9. </init-param>
  10. <!-- 项目部署到服务器,就会创建Servlet,大于等于0就会部署到服务器就创建,值越小越先创建 -->
  11. <load-on-startup>0</load-on-startup>
  12. </servlet>
  13. <servlet-mapping>
  14. <servlet-name>springmvc</servlet-name>
  15. <!-- 要拦截的客户端请求路径-->
  16. <url-pattern>/</url-pattern>
  17. </servlet-mapping>

在这里我们匹配模式写的是

  1. <!-- 要拦截的客户端请求路径-->
  2. <url-pattern>/</url-pattern>

这种方式会拦截静态资源比如.html、.js 等,不会拦截动态资源比如*.jsp
比如当访问HTML等静态资源时,报如下错误,说明HTML静态资源被拦截到了,在控制器里面又找不到以test.html匹配的路径于是报如下错误,其实我们是不想被拦截到的,希望交给Tomact容器去处理,然后返回给客户端。
Snipaste_2021-11-20_08-02-07.png
当访问JSP时,没有问题,说明没有拦截到JSP
image.png
有些公司进行URL匹配时,还会这样写

  1. <!-- 要拦截的客户端请求路径-->
  2. <url-pattern>*.do</url-pattern>

这样表示,只要当请求路径是.do结尾的请求才会被拦截。也就是说,无论是静态资源(html、CSS、JS、PNG、JPG等)、还是动态资源(JSP)都不会被拦截。
比如访问HTML
image.png
访问JSP
image.png
其实这种结果才是我们想要的,也就是当访问静态资源或者动态资源JSP时,还交给容器处理。只有以.do结尾的请求才交给控制器处理。

还有一种匹配模式是这样写的

  1. <!-- 拦截客户端所有请求路径-->
  2. <url-pattern>/*</url-pattern>

这种方式会拦截所有的请求路径,包括静态资源(html、CSS、JS、PNG、JPG等)、动态资源(*.jsp)
访问JSP
image.png
说明被拦截到了,交给控制器处理,由于控制器也没有对其进行处理报错了。

请求静态资源时
image.png
说明被拦截到了,交给控制器处理,由于控制器也没有对其进行处理报错了。
这才是要拦截所有的请求。这种写法通常用在Filter里面,比如设置编码,设置完后调用chain.doFilter过掉。

终上所述,最好的方案还是以*.do方式匹配的比较好。但是每次请求路径都要写.do还是比较烦的。比如

  1. https://example.com/user/add.do

如果可以直接能办到这样写,把.do去掉就好了

  1. https://example.com/user/add

我们在URL匹配中还是要这样写

  1. <url-pattern>/</url-pattern>

但这种方式会拦截到静态资源,我们只需把静态资源放开就可以了。
在applicationContext.xml文件里面配置如下信息

  1. <!-- DIspatcherServlet不想处理的请求都交给容器里面默认Servlet去处理,比如HTML等静态资源-->
  2. <mvc:default-servlet-handler />
  3. <!-- 保证所有的注解都能够使用,如果不加这句controller里面的注解都会失效-->
  4. <mvc:annotation-driven>
  5. <mvc:message-converters>
  6. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  7. <property name="defaultCharset" value="UTF-8" />
  8. </bean>
  9. </mvc:message-converters>
  10. </mvc:annotation-driven>

这样写就搞定啦。
当访问静态资源时,也没有问题了
image.png
补充:如果我们把web.xml里面的DIspatcherServlet去掉。当我们访问静态资源HTML时,Tomact里面会有一个DefaultServlet去处理对应的html文件,然后把静态资源文件返回给客户端。如果放问的是JSP,Tomact里面会有一个JspServlet处理JSP把对应的JSP资源处理返回给客户端,上面的配置就是说如果Controller里面没有写处理代码会转发到容器里面的Servlet处理。

把静态资源放开还有一种方式
在URL匹配中还是要这样写

  1. <url-pattern>/</url-pattern>

在applicationContext.xml文件里面配置如下信息

  1. <!-- mapping代表请求的路径。**表示所有的子目录都可以匹配-->
  2. <!-- Location表示:资源文件的位置-->
  3. <mvc:resources mapping="/asset/**" location="/asset/"/>
  4. <!-- 保证所有的注解都能够使用,如果不加这句controller里面的注解都会失效-->
  5. <mvc:annotation-driven>
  6. <mvc:message-converters>
  7. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  8. <property name="defaultCharset" value="UTF-8" />
  9. </bean>
  10. </mvc:message-converters>
  11. </mvc:annotation-driven>

image.png

请求处理后返回客户端的内容

请求处理后可以返回给客户端以下内容

  • 普通文本
  • HTML
  • JSON格式返回客户端
  • XML格式返回客户端
  • 转发到JSP返回
  • 重定向等
  • 文件(图片等),不需要处理已经交给默认的Servlet处理

普通文本、HTML

如果方法没有返回值,这种方式是我们以前搞Servlet处理方式

  1. @RequestMapping("testVoid")
  2. public void testVoid(HttpServletResponse response) throws IOException {
  3. response.setContentType("text/plain; charset=UTF-8");
  4. response.getWriter().write("哈哈哈");
  5. }

image.png
直接使用SpringMVC的方式

  1. @RequestMapping("testVoid1")
  2. @ResponseBody
  3. public String testVoid1(){
  4. return "哈哈哈哈";
  5. }

image.png
而且响应类型默认是text/html
image.png
如果返回的内容有HTML标签

  1. @RequestMapping("testVoid2")
  2. @ResponseBody
  3. public String testVoid2(){
  4. return "<h1>哈哈哈哈</h1>";
  5. }

image.png
浏览器会自动处理解析,因为响应类型默认是text/html
image.png

返回XML格式内容

  1. 添加依赖
    1. <!-- domain模型转XML字符串 -->
    2. <!-- XML 接口-->
    3. <dependency>
    4. <groupId>javax.xml.bind</groupId>
    5. <artifactId>jaxb-api</artifactId>
    6. <version>2.4.0-b180830.0359</version>
    7. </dependency>
    8. <!-- XML 接口的实现-->
    9. <dependency>
    10. <groupId>javax.xml</groupId>
    11. <artifactId>jaxb-impl</artifactId>
    12. <version>2.1</version>
    13. </dependency>
    注意:当然也必须有标签
    新建模型类 ```java import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.List;

//根元素 @XmlRootElement(name = “person”) public class Person { private String name; private Integer age; private Dog dog; private List goodDogs;

// 属性 @XmlAttribute(name = “name”) public String getName() { return name; }

  1. public void setName(String name) {
  2. this.name = name;
  3. }
  4. @XmlAttribute
  5. public Integer getAge() {
  6. return age;
  7. }
  8. public void setAge(Integer age) {
  9. this.age = age;
  10. }
  11. @XmlElement
  12. public Dog getDog() {
  13. return dog;
  14. }
  15. public void setDog(Dog dog) {
  16. this.dog = dog;
  17. }

// 引用类型要用 @XmlElement @XmlElement public List getGoodDogs() { return goodDogs; }

  1. public void setGoodDogs(List<Dog> goodDogs) {
  2. this.goodDogs = goodDogs;
  3. }

}

  1. ```java
  2. import javax.xml.bind.annotation.XmlAttribute;
  3. import javax.xml.bind.annotation.XmlRootElement;
  4. @XmlRootElement
  5. public class Dog {
  6. private String name;
  7. private Integer age;
  8. @XmlAttribute
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. @XmlAttribute
  16. public Integer getAge() {
  17. return age;
  18. }
  19. public void setAge(Integer age) {
  20. this.age = age;
  21. }
  22. }

返回方法

  1. @RequestMapping("/xml")
  2. @ResponseBody
  3. public Person login(){
  4. Person person = new Person();
  5. person.setName("lff");
  6. person.setAge(18);
  7. Dog dog = new Dog();
  8. dog.setAge(1);
  9. dog.setName("dog");
  10. Dog dog1 = new Dog();
  11. dog1.setAge(2);
  12. dog1.setName("dog2");
  13. ArrayList list = new ArrayList();
  14. list.add(dog);
  15. list.add(dog1);
  16. person.setGoodDogs(list);
  17. person.setDog(dog);
  18. return person;
  19. }

Snipaste_2021-11-20_13-08-32.png

返回JSON格式给客户端

配置依赖

  1. <!-- domain模型转JSON字符串 -->
  2. <dependency>
  3. <groupId>com.fasterxml.jackson.core</groupId>
  4. <artifactId>jackson-databind</artifactId>
  5. <version>2.11.0</version>
  6. </dependency>

新建模型类

  1. package com.lff.domain;
  2. import java.util.List;
  3. public class Person {
  4. private String name;
  5. private Integer age;
  6. private Dog dog;
  7. private List<Dog> goodDogs;
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. public Integer getAge() {
  15. return age;
  16. }
  17. public void setAge(Integer age) {
  18. this.age = age;
  19. }
  20. public Dog getDog() {
  21. return dog;
  22. }
  23. public void setDog(Dog dog) {
  24. this.dog = dog;
  25. }
  26. public List<Dog> getGoodDogs() {
  27. return goodDogs;
  28. }
  29. public void setGoodDogs(List<Dog> goodDogs) {
  30. this.goodDogs = goodDogs;
  31. }
  32. }
  1. package com.lff.domain;
  2. public class Dog {
  3. private String name;
  4. private Integer age;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. public Integer getAge() {
  12. return age;
  13. }
  14. public void setAge(Integer age) {
  15. this.age = age;
  16. }
  17. }

方法调用

  1. @RequestMapping("/json")
  2. @ResponseBody
  3. public Person json(){
  4. Person person = new Person();
  5. person.setName("lff");
  6. person.setAge(18);
  7. Dog dog = new Dog();
  8. dog.setAge(1);
  9. dog.setName("dog");
  10. Dog dog1 = new Dog();
  11. dog1.setAge(2);
  12. dog1.setName("dog2");
  13. ArrayList list = new ArrayList();
  14. list.add(dog);
  15. list.add(dog1);
  16. person.setGoodDogs(list);
  17. person.setDog(dog);
  18. return person;
  19. }

Snipaste_2021-11-20_13-28-39.png
上面无论返回的是JSON格式还是XML格式,如果返回有中文就会乱码,我们可以统一在applicationContext.xml设置。找一个比较全的设置乱码方式

  1. <mvc:annotation-driven>
  2. <mvc:message-converters>
  3. <!-- 如果控制器方法里面返回值是String类型的内容,就会设置UTF-8编码 -->
  4. <bean class="org.springframework.http.converter.StringHttpMessageConverter">
  5. <property name="defaultCharset" value="UTF-8"/>
  6. </bean>
  7. <!-- 如果控制器方法里面返回值是domain模型对象并且通过Jackson转成JSON字符串,就会设置UTF-8编码 -->
  8. <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
  9. <property name="defaultCharset" value="UTF-8"/>
  10. </bean>
  11. <!-- 如果控制器方法里面返回值是domain模型对象并且通过JAXB转成XML字符串,就会设置UTF-8编码 -->
  12. <bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter">
  13. <property name="defaultCharset" value="UTF-8"/>
  14. </bean>
  15. </mvc:message-converters>
  16. </mvc:annotation-driven>

a) 返回JSP给客户端

  • 使用ModelAndViev将数据和视图绑定在一起返回给客户端

新建测试JSP页面路径为/page/test1.jsp

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>Title</title>
  5. </head>
  6. <body>
  7. this is test1.jsp
  8. person name:${person.name}
  9. person age :${person.age}
  10. </body>
  11. </html>

处理客户端请求

  1. @RequestMapping("/jsp1") //注意次路径不要写以*.jsp结尾否则会被容器里面的Servlet处理
  2. public ModelAndView test1Jsp(){
  3. ModelAndView modelAndView = new ModelAndView();
  4. Person person = new Person();
  5. person.setName("lff");
  6. person.setAge(18);
  7. // 内部还是通过request.setAttribute的方式设置
  8. modelAndView.addObject("person",person);
  9. // 设置转发路径
  10. modelAndView.setViewName("/page/test1.jsp");
  11. return modelAndView;
  12. }

image.png
关于请求路径以及转发路径的问题
我们在RequestMapping里面写的是/jsp1。以/开头表示请求路径从http(s)://ip:端口/context_path/jsp1作为客户端请求路径

关于请求路径

在Java代码中,路径问题
假设请求路径是:”http://IP地址:端口/context_path/path1/path2/path3
我们设置转发路径为

  1. // 设置转发路径
  2. modelAndView.setViewName("/page/test1.jsp");

上面以/开头,表示转发时以context_path作为转发路径。所以最终的转发路径为:
http://IP地址:端口/context_path/page/test1.jsp
如果设置的转发路径为:

  1. // 设置转发路径
  2. modelAndView.setViewName("page/test1.jsp");

�不以/开头,在转发时会把当前请求路径的上一层路径作为参考路径。所以最终的转发路径为:
http://IP地址:端口/context_path/path1/path2/page/test1.jsp

�上面是在Java代码里面设置路径问题,如果是在JSP、HTML中呢?又有点区别:
假设请求路径还是是:”http://IP地址:端口/context_path/path1/path2/path3
在HTML中是这样设置请求路径的/page/test1.jsp

  1. 欢迎注册,请输入用户名
  2. <form method="POST" action="/page/test1.jsp">
  3. <p>姓名:<input type="text" name="name"></input></p>
  4. <p>年龄:<input type="text" name="age"></input></p>
  5. <p>密码:<input type="password" name="password"></input></p>
  6. <p><input type="submit" value="确定"></input></p>
  7. </form>

在HTML或者JSP中,以/开头,上面的表单会以http://IP地址:端口作为参考路径,所以最终的请求路径为:
http://IP地址:端口/page/test1.jsp
如果form表单请求路径为:page/test1.jsp。则请求路径会以当前请求路径的上一层路径作为参考路径。最终的请求路径为:http://IP地址:端口/context_path/path1/path2/page/test1.jsp。

b) 返回JSP给客户端

当请求方法返回字符串且请求方法上没有@ResponseBody时,返回的字符串作为转发路径

  1. @RequestMapping("/jsp1") //注意次路径不要写以*.jsp结尾否则会被容器里面的Servlet处理
  2. // @ResponseBody //注意不要加ResponseBody,如果加就会直接把返回的字符串返回到客户端
  3. public String test1Jsp(HttpServletRequest request){
  4. Person person = new Person();
  5. person.setName("lff");
  6. person.setAge(18);
  7. // 保存数据
  8. request.setAttribute("person",person);
  9. return "/page/test1.jsp"; //返回转发路径
  10. }

b) 重定向给客户端

  1. @RequestMapping("/jsp1") //注意次路径不要写以*.jsp结尾否则会被容器里面的Servlet处理
  2. public String test1Jsp(HttpServletRequest request){
  3. Person person = new Person();
  4. person.setName("lff");
  5. person.setAge(18);
  6. // 保存数据
  7. request.setAttribute("person",person); //这种方式是不能把数据传递给jsp的,因为是重定向会创建新的Request
  8. return "redirect:/page/test1.jsp"; //返回转发路径
  9. }

image.png
上面是获取不到保存的数据的,可以使用如下方式

  1. @RequestMapping("/jsp1") //注意次路径不要写以*.jsp结尾否则会被容器里面的Servlet处理
  2. public String test1Jsp(){
  3. return "redirect:/page/test1.jsp?name='lff'&age=18"; //返回转发路径
  4. }

image.png
也可以通过如下配置,配置请求路径和要找的资源位置

  1. <mvc:view-controller path="/jsp1" view-name="/page/test1.jsp" />

只有在控制器里面没有处理/jsp1路径时,才会走上面的配置,否则还是走控制器配置的路径。也就是控制器里面的优先级更高。

RestController

修饰控制器类的注解
@RestController //相当于@Controller + @ResponseBody。加这个注解相当于在控制器上加@Controller ,控制器的每个方法上加@ResponseBody。如果需要跳转页面就返回ModelAndViev