SpringMVC的请求接收与结果响应

SpringMVC2

接收参数的常用注解

  1. RequestParam注解
    作用:把请求中的指定名称的参数传递给控制器中的形参赋值
    属性:
    value:请求参数中的名称,指定请求参数名与方法参数名的映射关系(解决名称不一致的问题);
    required:请求参数中是否必须提供此参数,默认值是true,表示必须提供请求参数,若未传会抛异常,设为false则允许为空;
    defaultValue:如果没有传请求参数,使用该默认值。
java 复制代码
package com.qcby.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("/dept")
public class DeptController {
    /**
     * RequestParam注解
     */
    @RequestMapping("/save1.do")
    public String save(@RequestParam(value = "username", required = false, defaultValue = "abc") String name) {
        System.out.println("姓名:" + name);
        return "suc";
    }
}
  1. RequestBody注解
    作用:将整个请求体的内容作为字符串接收(注意:get方法不可以)
    required属性:表示是否必须有请求体,默认值是true

@requestBody注解常用的使用方式有两种:

  • 将json格式的数据绑定到对应的实体类中
    后端@RequestBody注解对应的类在将HTTP的输入流(含请求体)装配到目标类(即:@RequestBody后面 的类)时,会根据json字符串中的key来匹配对应实体类的属性,如果匹配一致且json中的该key对应的值符合(或可转换为)实体类的对应属性的类型要求时,会调用实体类的setter方法将值赋给该属性;
  • 将json格式的数据按照key值分别赋值在对应的字符串中
    使用method="post"提交时,参数不会拼在 URL 后面,而是被封装到请求体(Request Body)中,格式为 key=value&key=value。
html 复制代码
    <h3>请求参数绑定(@RequestBody注解方式一)</h3>
    ​<form action="/dept/save2.do" method="post">
        姓名:<input type="text" name="sname" /><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" name="aaa"/><br/>
    </form>

    <h3>请求参数绑定(@RequestBody注解方式二)</h3>
    ​<form action="/dept/save3.do" method="post">
        姓名:<input type="text" name="sname" /><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" name="aaa"/><br/>
    </form>
java 复制代码
package com.qcby.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/dept")
public class DeptController {
    /**
     * RequestBody注解,绑定到对应的实体类中
     */
    @RequestMapping("/save2.do")
    public String save2(@RequestBody String body){
        System.out.println("请求体内容:"+body);
        return "suc";
    }
    /**
     * RequestBody注解,别赋值在对应的字符串中
     */
    @RequestMapping("/save3.do")
    public String getUser(@RequestBody String sname,@RequestBody String age){
        System.out.println(sname);
        System.out.println(age);
        return "suc";
    }
}

打印结果:

  1. RequestHeader注解
    作用:获取指定请求头的信息
    value属性:请求头的名称

servlet 中获取指定请求头信息的方式:

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
    /**
     * servlet提供的获取请求头信息
     */
    @RequestMapping("/save7.do")
    public String save7(HttpServletRequest request, HttpServletResponse response) {

        System.out.println(request.getParameter("username"));
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headerName = (String) headerNames.nextElement();
            String headerValue = request.getHeader(headerName);
            System.out.println(headerName + ": " + headerValue);
        }
        return "suc";
    }
}

request 是 HttpServletRequest 类型的对象,代表客户端发送的 HTTP 请求,Enumeration<String> headerNames = request.getHeaderNames(); 即通过 getHeaderNames() 获取所有 HTTP 请求头名称的枚举对象,while (headerNames.hasMoreElements()) { ... } 循环遍历枚举对象,其中 hasMoreElements() 表示判断是否还有未处理的请求头名称,headerNames.nextElement(); 获取下一个请求头的名称,request.getHeader(headerName); 根据名称获取对应的请求头值。

html 复制代码
    <h3>获取请求头信息(servlet提供)</h3>
    <form action="/user/save7.do" method="post">
        姓名:<input type="text" name="username" /><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" /><br/>
    </form>

打印结果:

Spring 框架提供的 @RequestHeader 注解用于获取请求头中指定字段的值

java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
    /**
     * @RequestHeader 注解
     */
    @RequestMapping("/save8.do")
    public String save8(@RequestHeader("cookie") String headerValue) {
        System.out.println(headerValue);
        return "suc";
    }
}

其中参数"cookie"表示获取请求头中名为Cookie的字段,注意是获取整个Cookie请求头的原始字符串

html 复制代码
    <h3>获取请求头信息(@RequestHeader 注解)</h3>
    <form action="/user/save8.do" method="post">
        姓名:<input type="text" name="username" /><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" /><br/>
    </form>

打印结果:

  1. CookieValue注解
    作用:用于从请求携带的Cookie中直接获取指定名称Cookie的值
    value属性:cookie的名称
java 复制代码
@Controller
@RequestMapping("/user")
public class UserController {
	/**
     * CookieValue注解
     */
    @RequestMapping("/save9.do")
    public String save9(@CookieValue(value = "JSESSIONID") String cookie){
        System.out.println("值:"+cookie);
        return "suc";
    }
}

@CookieValue 注解会自动从所有Cookie中提取指定名称(value = "JSESSIONID")的单个Cookie的具体值

html 复制代码
    <h3>获取请求头cookie信息(@CookieValue 注解)</h3>
    <form action="/user/save9.do" method="post">
        姓名:<input type="text" name="username" /><br/>
        年龄:<input type="text" name="age" /><br/>
        <input type="submit" value="提交" /><br/>
    </form>

打印结果:

  1. PathVaribale注解
    作用:获取 URL 路径中的占位符参数(适用于 RESTful 风格的 URL)
    例如:url中有/delete/{id},{id}就是占位符
    value属性:指定url中的占位符名称,若方法参数名与占位符名一致可省略

Restful 风格的 URL:请求路径一样,可以根据不同的请求方式去执行后台的不同方法

@GetMapping:映射 GET 请求,用于查询资源

@PostMapping:映射 POST 请求,用于创建新资源

@PutMapping:映射 PUT 请求,用于全量更新资源

@DeleteMapping:映射 DELETE 请求,用于删除资源

restful风格的URL优点:结构清晰、符合标准、易于理解、扩展方便

java 复制代码
package com.qcby.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
//@RequestMapping("/emp")
public class EmpController{

    /**
     * 保存
     */
    @RequestMapping(path ="/emp",method = RequestMethod.POST)
    public String save(){
        System.out.println("保存员工...");
        return "suc";
    }

    /**
     * 查询所有
     */
    @RequestMapping(path ="/emp", method = RequestMethod.GET)
    public String findAll(){
        System.out.println("查询员工...");
        return "suc";
    }

    /**
     * 查询所有
     */
    @RequestMapping(path = "/emp/{id}",method = RequestMethod.GET)
    public String findById(@PathVariable(value = "id") Integer id){
        System.out.println("通过id查询员工..."+id);
        return "suc";
    }
}
html 复制代码
    <h3>Restful风格的URL</h3>
    <form action="/emp" method="post">
        <input type="submit" value="保存员工"><br/>
    </form>
    <form action="/emp" method="get">
        <input type="submit" value="查询员工"><br/>
    </form>
    <form action="/emp/1" method="get">
        <input type="submit" value="通过id查询员工"><br/>
    </form>

打印结果:

响应数据和结果视图

  1. 返回String
java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * 返回字符串(常用)
     */
    @RequestMapping("/save1.do")
    public String save1(){
        System.out.println("执行了save1...");
        return "suc";
    }
}
  1. 返回值是void
    如果控制器的方法返回值编写成void,SpringMVC 不会自动进行视图解析或数据处理,默认查找JSP页面没有找到,执行程序报404的异常
    解决方式:可以使用请求转发或者重定向跳转到指定的页面,而非依赖 Spring MVC 的视图解析器自动跳转

需要使用 Servlet 规范中的原生 API 获取请求信息和处理响应,三种常见的响应方式:

  • 通过 HttpServletRequest 的 getRequestDispatcher() 方法实现请求转发,可以访问/WEB-INF目录下的资源,以及可以携带request域中的数据到目标资源;
  • 通过 HttpServletResponse 的 sendRedirect() 方法实现重定向,需要注意的是不能直接访问/WEB-INF目录下的资源,且request域中的数据会丢失;
  • 通过 HttpServletResponse 的输出流直接向客户端输出数据,不经过其他资源跳转。
java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * 返回值是void
     */
    @RequestMapping("/save2.do")
    public void save2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("执行了save2...");
        //请求转发
         request.getRequestDispatcher("/WEB-INF/pages/suc.jsp").forward(request,response);
        //重定向, request.getContextPath() 用于获取上下文路径
        //response.sendRedirect(request.getContextPath() + "/index.jsp");
        // 使用response对象直接向客户端输出响应数据
        //response.getWriter().print("hello");
        return;
    }
}
  1. 返回值是ModelAndView对象
    ModelAndView 是 SpringMVC 提供的一个对象,可同时封装模型数据和视图信息,适合需要在一个对象中同时处理数据和视图的场景
java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * 返回ModelAndView对象
     */
    @RequestMapping("/save3.do")
    public ModelAndView save3(){
        System.out.println("执行了save3...");
        // 创建mv对象
        ModelAndView mv = new ModelAndView();
        // 把一些数据,存储到mv对象中
        mv.addObject("msg","用户名或者密码已经存在");
        // 设置逻辑视图的名称
        mv.setViewName("suc");
        // 也支持redirect/forward
        // mv.setViewName("redirect:/index.jsp");
        return mv;
    }
}

补充另一种拆开的方式,返回值是String,视图解析器跳转至对应视图,参数列表中携带model来返回数据内容,代码示例:

java 复制代码
@Controller
@RequestMapping("/mtype")
public class MtypeController {
    @RequestMapping("/list")
    public String selectpage(MtypeQuery mq, Model model){

        Page<Mtype> page = mtypeService.selectObjectByCondition(mq);
        model.addAttribute("page", page);
        return "mtype";
    }
}
  1. SpringMVC 框架提供的forward请求转发
java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * 返回String
     * SpringMVC框架提供的请求转发
     */
    @RequestMapping("/save4.do")
    public String save4(){
        System.out.println("执行了save4...");
        return "forward:/WEB-INF/pages/suc.jsp";
    }
}
  1. SpringMVC 框架提供的redirect请求转发
java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * 返回String
     * SpringMVC框架提供的重定向
     */
   @RequestMapping("/save5.do")
    public String save5(){
        System.out.println("执行了save5...");
        return "redirect:save1.do";
       // 也可重定向到外部URL但无法访问WEB-INF下的资源
       //return "redirect:https://www.baidu.com";
    }
}

前端编写

xml 复制代码
    <h3>请求转发与重定向</h3>
    <form action="/redict/save1.do" method="get">
        <input type="submit" value="执行"><br/>
    </form>
    <form action="/redict/save2.do" method="get">
        <input type="submit" value="执行"><br/>
    </form>
    <form action="/redict/save3.do" method="get">
        <input type="submit" value="执行"><br/>
    </form>
    <form action="/redict/save4.do" method="get">
        <input type="submit" value="执行"><br/>
    </form>
    <form action="/redict/save5.do" method="get">
        <input type="submit" value="执行"><br/>
    </form>

打印结果:

  1. ResponseBody响应json数据(重要)

首先需要导入坐标依赖,引入JSON 序列化依赖

xml 复制代码
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>

@ResponseBody的使用本质是 "标记返回值需转为响应体",ResponseBody响应json数据后台代码编写有三种方式,使得返回值会被序列化为 JSON

第一种方式 @ResponseBody 注解加到返回值前

java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    /**
     * ResponseBody响应json数据(重要)
     * 异步的数据交互
     */
    @RequestMapping("/save6.do")
    public @ResponseBody User save6(@RequestBody User user){
        System.out.println(user);
        // 模拟,调用业务层代码
        user.setUsername("hello");
        user.setAge(100);
        // 把user对象转换成json字符串,再响应,response.getWriter().print()
        return user;
    }
}

第二种方式 @ResponseBody 注解加到方法上

java 复制代码
@Controller
@RequestMapping("/redict")
public class ReController {
    // 方法上单独使用@ResponseBody
    @RequestMapping("/save7.do")
    @ResponseBody  // 仅当前方法返回数据(不跳转视图)
    public User save7(@RequestBody User user) {
        System.out.println(user);
        user.setUsername("hello");
        user.setAge(100);
        return user;  // 返回的User对象会被转换为JSON响应
    }
}

第三种方式 @ResponseBody 注解加到类上,即类上使用@RestController,等价于@Controller + @ResponseBody

java 复制代码
package com.qcby.controller;

import com.qcby.model.User;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/test")
public class TestController {

    // 方法上无需再添加@ResponseBody
    @RequestMapping("/save1.do")
    public User save6(@RequestBody User user) {
        System.out.println(user);
        user.setUsername("hello");
        user.setAge(100);
        return user;  // 返回的User对象会被转换为JSON响应
    }
}

前端jsp代码编写

html 复制代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>请求参数绑定</title>
    <%--引入jq,使用阿里云的jQuery CDN(无integrity校验,稳定可靠) --%>
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js" type="text/javascript"></script>

    <script>
        // 页面加载
        $(function(){
            // 单击事件
            $("#btn1").click(function(){
            // 发送ajax的请求
                $.ajax({
                    type: "post",
                    url: "/redict/save6.do",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"haha","age":"20"}',
                    dataType: "json",
                    success:function(d){
                        // 编写很多代码
                        alert(d.username+" - "+d.age);
                    }
                });
            });
            $("#btn2").click(function(){
                // 发送ajax的请求
                $.ajax({
                    type: "post",
                    url: "/redict/save7.do",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"haha","age":"20"}',
                    dataType: "json",
                    success:function(d){
                        // 编写很多代码
                        alert(d.username+" - "+d.age);
                    }
                });
            });

            $("#btn3").click(function(){
                // 发送ajax的请求
                $.ajax({
                    type: "post",
                    url: "/test/save1.do",
                    contentType:"application/json;charset=UTF-8",
                    data:'{"username":"haha","age":"20"}',
                    dataType: "json",
                    success:function(d){
                        // 编写很多代码
                        alert(d.username+" - "+d.age);
                    }
                });
            });
        });

    </script>

</head>
<body>

    <h2>响应数据和结果视图</h2>
    <h3>返回值是String</h3>
    <a href="/redict/save1.do" >返回String</a><br/>
    ​
    <h3>返回值是void</h3>
    <a href="/redict/save2.do" >返回void</a><br/>
    ​
    <h3>返回值是ModelAndView</h3>
    <a href="/redict/save3.do" >返回ModelAndView</a><br/>
    ​
    <h3>请求转发返回值是String</h3>
    <a href="/redict/save4.do" >返回值是String</a><br/>
    ​
    <h3>重定向返回值是String</h3>
    <a href="/redict/save5.do" >返回值是String</a><br/>
    ​
    <h3>异步的数据交互方式1</h3>
    <input type="button" value="ajax交互" id="btn1"><br/>

    <h3>异步的数据交互方式2</h3>
    <input type="button" value="ajax交互" id="btn2"><br/>

    <h3>异步的数据交互方式3</h3>
    <input type="button" value="ajax交互" id="btn3"><br/>

</body>
</html>

需要注意的是 DispatcherServlet 会拦截到所有的资源,导致静态资源也会被拦截到,从而不能被使用,需要配置静态资源不进行拦截,在 springmvc.xml 配置文件添加如下配置:

xml 复制代码
    <!-- 设置静态资源不过滤 -->
    <mvc:resources location="/css/" mapping="/css/**"/>  <!-- 样式 -->
    <mvc:resources location="/images/" mapping="/images/**"/>  <!-- 图片 -->
    <mvc:resources location="/js/" mapping="/js/**"/>  <!-- javascript -->

location元素表示webapp目录下的包下的所有文件,mapping元素表示以/static开头的所有请求路径

响应结果:

后端打印结果:

相关推荐
风象南4 小时前
SpringBoot 「热补丁加载器」:线上紧急 bug 临时修复方案
后端
Victor3564 小时前
Redis(43)Redis哨兵(Sentinel)是什么?
后端
Victor3565 小时前
Redis(42)Redis集群如何处理键的迁移?
后端
CHEN5_026 小时前
【CouponHub开发记录】SpringAop和分布式锁进行自定义注解实现防止重复提交
java·分布式·spring·项目
编啊编程啊程6 小时前
Netty从0到1系列之Selector
java·spring boot·spring cloud·java-ee·kafka·maven·nio
程序员爱钓鱼7 小时前
Go语言实战案例- Redis实现简单排行榜
后端·google·go
angushine7 小时前
Spring Boot 工程启动时自动执行任务方法
java·spring boot·后端
冷雨夜中漫步8 小时前
ClickHouse常见问题——ClickHouseKeeper配置listen_host后不生效
java·数据库·clickhouse