SpringMVC系列四: Rest-优雅的url请求风格

上一讲, 我们学习的是SpringMVC系列三: Postman(接口测试工具)

现在打开springmvc项目

在这里插入图片描述

💞Rest基本介绍

●说明

1.REST:Representational State Transfer. (资源)表现层状态转化. 是目前流行的请求方式. 它结构清晰, 很多网站使用.
2.HTTP协议里面, 四个表示操作方式的动词: GET, POST, PUT, DELETE, 它们分别对应四种基本操作: GET用来获取资源, POST用来新建资源, PUT用来更新资源, DELETE用来删除资源
3.实例. 传统的请求方法:
getBook?id=1 GET
delete?id=1 GET
update POST
add POST
4.说明: 传统的url是通过参数来说明crud的类型, rest是通过get/post/put/delete来说明crud的类型

REST的核心过滤器
1.当前的浏览器只支持post/get请求, 因此为了得到put/delete的请求方式需要使用Spring提供的HiddenHttpMethodFilter过滤器进行转换.
2.HiddenHttpMethodFilter:浏览器form表单只支持GETPOST请求, 而DELETE, PUTmethod并不支持, Spring添加了一个过滤器, 可以将这些请求转换为标准的http方法, 使得支持GET, POST, PUTDELETE请求.
3.HiddenHttpMethodFilter只能对post请求方式进行转换.
4.这个过滤器需要在web.xml中配置

💞Rest风格的url-完成增删改查

需求说明

小明去书店买书, 完成购买书籍的增删改查

代码实现

1.修改web.xml, 配置HiddenHttpMethodFilter

<!--配置HiddenHttpMethodFilter
1.作用是 把 以post方式提交的delete和put请求, 进行转换
2.配置url-pattern 是 /* 表示请求都经过 hiddenHttpMethodFilter的过滤
3.后面通过debug源码, 会看的很清楚.
-->
<filter>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>hiddenHttpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

2.修改springDispatcherServlet-serlvet.xml 添加配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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">

<!--加入两个常规配置-->
<!--支持SpringMVC的高级功能, 比如JSR303校验, 映射动态请求-->
<mvc:annotation-driven></mvc:annotation-driven>
<!--将springmvc不能处理的请求, 交给tomcat处理, 比如css, js-->
<mvc:default-servlet-handler/>

3.在web路径下创建rest.jsp, 注意引入jquery, 测试查询/添加/删除/修改

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>rest测试</title>
</head>
<body>
<h3>Rest风格的crud操作案例</h3>
<br/><hr>
<h3>rest风格的url 查询书籍[get]</h3>
<a href="?">点击查询书籍</a>
<br/><hr>
<h3>rest风格的url 添加书籍[post]</h3>
<form action="?" method="?">
    name:<input name="bookName" type="text"/><br/>
    <input type="submit" value="添加书籍">
</form>
<br/><hr>
<h3>rest风格的url 删除一本书</h3>
<a href="?" id="?">删除指定id的书</a>
<br/><hr>
<h3>rest风格的url 修改书籍[put]</h3>
<form action="?">
    <input type="submit" value="修改书籍">
</form>
</body>
</html>

4.在com.zzw.web.rest下, 创建BookHandler.java

1.完成查询

 //BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {

    //查询[GET]
    @GetMapping(value = "/book/{id}")
    public String getBook(@PathVariable("id") String id) {
        System.out.println("查询书籍 id=" + id);
        return "success";
    }
}

5.前端修改请求地址

<h3>rest风格的url 查询书籍[get]</h3>
<a href="user/book/200">点击查询书籍</a>

2.完成添加
@PostMapping(value = "/book") @GetMapping(value = "/book/{id}")不重复

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {

    //查询[GET]
    @GetMapping(value = "/book/{id}")
    public String getBook(@PathVariable("id") String id) {
        System.out.println("查询书籍 id=" + id);
        return "success";
    }

    //添加[POST]
    @PostMapping(value = "/book")
    public String addBook(String bookName) {
        System.out.println("添加书籍 bookName=" + bookName);
        return "success";
    }
}

前端修改请求地址

<h3>rest风格的url 添加书籍[post]</h3>
<form action="user/book" method="post">
    name:<input name="bookName" type="text"/><br/>
    <input type="submit" value="添加书籍">
</form>

3.完成删除

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
    //查询[GET]
    @GetMapping(value = "/book/{id}")
    public String getBook(@PathVariable("id") String id) {
        System.out.println("查询书籍 id=" + id);
        return "success";
    }

    //添加[POST]
    @PostMapping(value = "/book")
    public String addBook(String bookName) {
        System.out.println("添加书籍 bookName=" + bookName);
        return "success";
    }

    //删除[DELETE]
    @RequestMapping(value = "/book/{id}", method = RequestMethod.DELETE)
    public String deleteBook(@PathVariable("id") String id) {
        System.out.println("删除书籍 id=" + id);
        //return "success";//[如果这样写会报错 JSP 只允许 GET、POST 或 HEAD]
        //解读
        //1. redirect:/user/success重定向
        //2. 会被解析成 /工程路径/user/success
        return "redirect:/user/success";//提示: 重定向不能重定向到WEB-INF下的资源, 所以需要借助successGeneral方法
    }

    //如果请求时 /user/success, 就转发到 success.jsp
    //successGeneral 对应的url http://localhost:8080/springmvc/user/success
    @RequestMapping(value = "/success")
    public String successGeneral() {
        return "success";//由该方法 转发到success.jsp页面
    }
}

知识点:
1.web路径/script目录下存放jquery文件, jquery复习

2.为什么前端做了一个操作后, 就可以被过滤器过滤处理, 定位到后端delete方法? 回答: HiddenHttpMethodFilter机制

3.return “success”; 会报以下错误, JSP只允许GET,POST或HEAD
在这里插入图片描述


前端修改 this是dom对象

<head>
    <title>rest测试</title>
    <%--script标签建议放在head内--引入jquery--%>
    <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
        $(function () {//当页面加载完成后就执行
            // alert("ok...");
            //给删除超链接绑定一个点击事件
            $("#deleteBook").click(function () {
                // alert("点击....");
                //我们自己定义一个提交的行为
                $("#hiddenForm").attr("action", this.href);
                $("input:hidden").val("DELETE");
                $("#hiddenForm").submit();
                return false;//改变点击超链接的行为, 不再提交
            })
        });
    </script>
</head>
<body>
<h3>rest风格的url 删除一本书</h3>
<%--解读
 1. 默认情况下, <a href="user/book/600">删除指定id的书</a> 是get请求
 2. 怎么样将 get 请求转成 springmvc 可以识别的 delete 请求, 就要考虑HiddenHttpMethodFilter
    public static final String DEFAULT_METHOD_PARAM = "_method";
    -------------------------------------------------------------------------------------------------------------
    if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
        String paramValue = request.getParameter(this.methodParam);
        if (StringUtils.hasLength(paramValue)) {
            String method = paramValue.toUpperCase(Locale.ENGLISH);
            if (ALLOWED_METHODS.contains(method)) {
                requestToUse = new HttpMethodRequestWrapper(request, method);
            }
        }
    }
    -------------------------------------------------------------------------------------------------------------
    private static final List<String> ALLOWED_METHODS =
			Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),
					HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));
 3. 从上面代码可以看到 HiddenHttpMethodFilter 过滤器可以对以Post方式提交的delete, put, patch进行转换
    , 转换成springmvc可以识别的 RequestMethod.DELETE / RequestMethod.PUT...
 4. 我们需要将 get <a href="user/book/600">删除指定id的书</a> 以 post方式提交给后端handler, 这样过滤器才会生效
 5. 我们可以通过jquery来处理--引入jquery
--%>
<a href="user/book/600" id="deleteBook">删除指定id的书</a>
<form action="" method="post" id="hiddenForm">
    <input type="hidden" name="_method"/>
</form>
</body>

4.完成修改

//BookHandler 处理rest风格的请求-增删改查
@RequestMapping(value = "/user")
@Controller
public class BookHandler {
    //修改[PUT]
    @PutMapping(value = "/book/{id}")
    public String updateBook(@PathVariable("id") String id) {
        System.out.println("修改书籍 id=" + id);
        return "redirect:/user/success";
    }
}

前端修改请求代码

<h3>rest风格的url 修改书籍[put]</h3>
<form action="user/book/666" method="post">
    <input type="hidden" name="_method" value="PUT"/>
    <input type="submit" value="修改书籍"/>
</form>

HiddenHttpMethodFilter机制

打断点, 进行debug
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意事项和细节

1.HiddenHttpMethodFilter, 在将post转成delete / put请求时, 是按_method参数名 来读取的
2.如果web项目是运行在Tomcat8及以上, 会发现被过滤成DELETEPUT请求, 到达控制器时能顺利执行, 但是返回时(forward)会报HTTP 405的错误提示: JSP 只允许 GET、POST 或 HEAD

  1. 解决方式1: 使用Tomcat7
  2. 解决方式2: 将请求转发(forward)改为请求重定向(redirect): 重定向到一个Handler, 由Handler转发到页面
    在这里插入图片描述

3.页面测试时, 如果出现点击修改书籍, 仍然走的是删除url, 是因为浏览器原因(缓存等原因).

💞课后作业

需求说明
小王去商超买衣服, 完成购买衣服的增删改查

1.在web路径下创建restBuyClothes.jsp, 注意引入jquery, 测试查询/添加/删除/修改

<head>
    <title>购买衣服</title>
    <%--引入jquery--%>
    <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
</head>
<body>
<h3>rest风格的url 挑选衣服[get]</h3>
<a href="?">点击挑选衣服</a>
<br/><hr>
<h3>rest风格的url 添加衣服[post]</h3>
<a href="?">点击添加衣服</a>
<form action="?" method="post">
    clothes: <input name="clothes" type="text"><br/>
    <input type="submit" value="添加衣服">
</form>
<br/><hr>
<h3>rest风格的url 删除一件衣服[delete]</h3>
<a href="?" id="deleteClothes">删除一件衣服</a>
<form action="" method="post" id="deleteForm">
    <input type="hidden" name="_method"/>
</form>
<br/><hr>
<h3>rest风格的url 修改衣服[get]</h3>
<form action="?" method="post">
    <input type="hidden" name="_method">
</form>
</body>

2.在com.zzw.web.rest下, 创建ClothesHandler.java

1.完成查询
@PostMapping(value = "/clothes") @GetMapping(value = "/clothes/{brand}")不重复

@RequestMapping(value = "/user")//处理Rest风格的请求 增删改查
@Controller
public class ClothesHandler {

    //挑选[GET]
    @GetMapping(value = "/clothes/{brand}")
    public String queryClothes(@PathVariable("brand") String brand) {
        System.out.println("挑选衣服 brand=" + brand);
        return "success";
    }
}

.前端修改请求

<h3>rest风格的url 挑选衣服[get]</h3>
<a href="user/clothes/阿迪达斯">点击挑选衣服</a>

2.完成添加

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求

    //挑选[GET]
    @GetMapping(value = "/clothes/{brand}")
    public String queryClothes(@PathVariable("brand") String brand) {
        System.out.println("挑选衣服 brand=" + brand);
        return "success";
    }

    //添加[POST]
    @PostMapping(value = "/clothes")
    public String addClothes(String brand) {
        System.out.println("添加衣服 brand=" + brand);
        return "success";
    }
}

.前端修改请求

<h3>rest风格的url 添加衣服[post]</h3>
<form action="user/clothes" method="post">
    clothes: <input name="brand" type="text"><br/>
    <input type="submit" value="添加衣服">
</form>

3.完成删除

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求

    //挑选[GET]
    @GetMapping(value = "/clothes/{brand}")
    public String queryClothes(@PathVariable("brand") String brand) {
        System.out.println("挑选衣服 brand=" + brand);
        return "success";
    }

    //添加[POST]
    @PostMapping(value = "/clothes")
    public String addClothes(String brand) {
        System.out.println("添加衣服 brand=" + brand);
		//return "success";
        return "redirect:/user/success";
    }

    @RequestMapping(value = "/success2")
    public String successGeneral() {
        return "success";
    }
}

.前端修改请求

<head>
    <title>购买衣服</title>
    <%--引入jquery--%>
    <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script>
    <script type="text/javascript">
        $(function () {
            // alert("123");
            $("#deleteClothes").click(function () {
                // alert("ok..");
                $("#deleteForm")[0].action = this.href;
                $("input:hidden")[0].value = "DELETE";
                $("#deleteForm").submit();
                return false;
            })
        })
    </script>
</head>
<body>
<h3>rest风格的url 删除一件衣服[delete]</h3>
<a href="user/clothes/361" id="deleteClothes">删除一件衣服</a>
<form action="" method="post" id="deleteForm">
    <input type="hidden" name="_method"/>
</form>
</body>

4.完成修改

@RequestMapping(value = "/user")
@Controller
public class ClothesHandler {//演示Rest风格的请求

    //挑选[GET]
    @GetMapping(value = "/clothes/{brand}")
    public String queryClothes(@PathVariable("brand") String brand) {
        System.out.println("挑选衣服 brand=" + brand);
        return "success";
    }

    //添加[POST]
    @PostMapping(value = "/clothes")
    public String addClothes(String brand) {
        System.out.println("添加衣服 brand=" + brand);
		//return "success";
        return "redirect:/user/success";
    }

    @RequestMapping(value = "/success2")
    public String successGeneral() {
        return "success";
    }

    //修改[PUT]
    @PutMapping(value = "/clothes/{brand}")
    public String updateClothes(@PathVariable("brand") String brand) {
        System.out.println("修改衣服 brand=" + brand);
        return "redirect:/user/success2";
    }
}

.前端修改请求

<body>
<h3>rest风格的url 修改衣服[get]</h3>
<form action="user/clothes/李宁" method="post">
    <input type="hidden" name="_method" value="PUT">
    <input type="submit" value="修改衣服"/>
</form>
</body>

在这里插入图片描述

下一讲, 我们学习 SpringMVC系列五: SpringMVC映射请求数据

  • 14
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

~ 小团子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值