(9)使用RESTful风格时开启静态资源的映射和请求方式转换的配置

REST风格

资源

资源是一种看待服务器的方式,服务器可以看作是由很多离散的资源(文件)组成,一个资源可以由一个或多个URI来标识,URI既是资源的名称也是资源在Web上的地址

  • 对某个资源感兴趣的客户端应用只需要通过访问资源的URI就能与其进行交互, URI就是每一个资源的独一无二的识别符

资源的表述: 对于资源在某个特定时刻的表现形式可以用不同的格式描述, 以便资源在客户端(请求)-服务器端(响应)之间转移/交换

  • 文本资源可以用txt格式、HTML格式、XML格式、JSON格式,甚至是二进制格式表现,具体采用什么格式可以通过协商机制来确定

资源状态转移: 资源(数据)在客户端和服务器传输时格式会发生转化, 通过改变资源的格式状态和操作资源的表述(增删改查)来间接实现操作资源的目的

  • HTTP协议是一个无状态协议,资源所有的状态都保存在服务器端,如果客户端想要操作服务器的资源,就需要改变对应资源在服务器中的状态/格式

RESTful

REST风格 是一种将URL地址中从前到后的各个单词使用斜杠分开的风格设计,不再将请求参数放到?后面,而是将请求参数作为URL地址的一部分

  • 优点: 请求地址书写简化,隐藏了资源的访问行为,无法通过地址得知该资源是何种操作
  • 按照REST风格访问资源称为RESTful,面对相同的URL地址可以使用行为动作区分对资源进行了何种操作,GET(查询),POST(新增),PUT(修改),DELETE(删除)
操作传统方式REST风格提交的数据响应的数据
根据id查询操作getUserById?id=1user/1+GET请求方式一般以键值对格式提交数据状态码: 200
响应体:单条或多条查询信息
新增操作saveUseruser+POST请求方式以键值对或JSON格提交数据状态码: 201(或200)
响应体:新增后的数据
根据id删除操作deleteUser?id=1user/1+DELETE请求方式一般以键值对格式提交数据状态码: 204
响应体: 无
更新操作updateUseruser+PUT请求方式以键值对或JSON格式提交数据状态码: 201(或200)
响应体:修改后的数格

静态资源的映射

DefaultServlet是Tomcat中专门处理静态资源(除jsp和servlet)请求的Servlet, 遇到这些静态资源请求时Tomcat会在服务器下找到这个资源并返回

  • 所有web工程的web.xml文件的配置都是继承于Tomcat服务器的web.xml配置,如果我们修改了当前web工程的配置,就会覆盖Tomcat服务器的web.xml配置

DispatcherServlet的url-pattern=/表示代替DefaultServlet处理静态资源请求

  • DispatcherServlet前端控制器处理请求的方式是看哪个控制器方法的请求映射的路径是这个静态资源名,找到则执行控制器方法找不到则报错
<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup>
</servlet><servlet-mapping><servlet-name>default</servlet-name><!--DefaultServlet可以处理除jsp外的所有请求--><url-pattern>/</url-pattern>
</servlet-mapping>

需求: 当处理访问静态资源(html、js、css、jpg)的请求时先由前端控制器处理,如果找不到请求映射的控制器方法就交由默认的DefaultServlet处理,还找不到则报错

<!--设置所有的请求由默认的DefaultServlet处理,此时前端控制器就不能处理请求了-->
<mvc:default-servlet-handler />
<!--开启mvc注解驱动,当处理访问静态资源的请求时先由前端控制器处理,如果找不到请求映射的控制器方法就交由默认的DefaultServlet处理-->
<mvc:annotation-driven />

请求转换过滤器

注册HiddenHttpMethodFilter

HTTP协议中有GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE几种请求,但是浏览器只支持发送GET和POST两种方式的请求

  • 在浏览器地址栏上发起的都是GET请求

  • 使用表单的method属性只能设置GET和POST两种请求方式,如果method属性值设置了其他的请求方式或者不设置请求方式那么此时发起的都是GET请求

<form th:action="@{/testPut}" method="put"><!--表单实际发起的是GET请求--><input type="submit" value="测试form表单是否能够发送put或delete请求方式">
</form>

使用SpringMVC提供的HiddenHttpMethodFilter可以帮助我们将POST请求转换为DELETE,PUT.PATCH方式的请求,但是需要满足两个条件

  • 第一: 由于HiddenHttpMethodFilter只能转换POST请求,所以当前请求的请求方式必须为POST,那就需要创建一个表单
  • 第二: POST请求必须携带_ method请求参数,value值可以是DELETE,PUT,PATCH,一般通过隐藏域隐藏_ method请求参数

第一步: 在web.xml中注册HiddenHttpMethodFilter过滤器,这个过滤器必须要在CharacterEncodingFilter之后执行

  • CharacterEncodingFilter过滤器设置字符集的编码时,要求request对象之前不能有任何获取请求参数的相关操作,否则设置的字符集编码无效无效
  • HiddenHttpMethodFilter恰恰有一个获取_ method请求参数的值的操作request.getParameter(this.methodParam)
<!--把POST请求转化为其他请求的Filter-->
<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>

第二步: 使用form表单发起POST请求,同时携带请求参数_ method,请求参数的值就是我们实际要发送的请求方式

<!--将POST请求转换为PUT请求 -->
<form th:action="@{/user}" method="post"><input type="hidden" name="_method" value="put"><input type="submit" value="修改用户信息">
</form><!--将POST请求转换为DELETE请求 -->
<form th:action="@{/user/1}" method="post"><!--_method请求参数的value值为最终的请求方式 --><input type="hidden" name="_method" value="delete"/><input type="submit" value="删除用户信息">
</form>

HiddenHttpMethodFilter原理

HiddenHttpMethodFilter过滤器会将请求参数_ method的值全部大写取替换request中method属性的值,因此请求参数_method的值才是最终的请求方式

public class HiddenHttpMethodFilter extends OncePerRequestFilter {// ALLOWED_METHODS是个List集合,集合中的元素是PUT,DELETE,PATCHprivate static final List<String> ALLOWED_METHODS =Collections.unmodifiableList(Arrays.asList(HttpMethod.PUT.name(),//HttpMethod是枚举类型HttpMethod.DELETE.name(), HttpMethod.PATCH.name()));public static final String DEFAULT_METHOD_PARAM = "_method";private String methodParam = DEFAULT_METHOD_PARAM;public void setMethodParam(String methodParam) {Assert.hasText(methodParam, "'methodParam' must not be empty");this.methodParam = methodParam;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)throws ServletException, IOException {// 将原生的request做一个备份,便于后续操作HttpServletRequest requestToUse = request;// 判断当前的请求方式是否是POST请求,并且请求域中有没有异常对象,满足条件则执行过滤规则if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {// this.methodParam的值是"_method",所以就是获取请求参数_method的值即我们指定的请求方式String paramValue = request.getParameter(this.methodParam);// 判断请求参数_method的值是否不为null或空字符串,满足条件则对备份的requestToUse对象重新包装if (StringUtils.hasLength(paramValue)) {// 是个List集合,元素是PUT,DELETE,PATCH// 将我们指定的请求方式转换为大写String method = paramValue.toUpperCase(Locale.ENGLISH);// 判断ALLOWED_METHODS集合中是否包含我们指定的请求方式if (ALLOWED_METHODS.contains(method)) {// 重新包装一个请求对象,重写了getMethod方法即改掉了method属性的值requestToUse = new HttpMethodRequestWrapper(request, method);}}}// 放行执行下一个过滤器或者Servlet,如果当前请求不是POST请求,此时的requestToUse对象等同于原来request对象// 如果当前请求是POST请求,此时的requestToUse对象是我们包装后的request对象,将method属性的值替换成我们指定的请求方式了filterChain.doFilter(requestToUse, response);}// 对原生的request对象进行包装private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {// 请求方式private final String method;public HttpMethodRequestWrapper(HttpServletRequest request, String method) {super(request);// 此时的method属性的值_method属性的值即我们指定的请求方式this.method = method;}@Override// 重写父类的getMethod方法,以后我们调用request对象getMethod方法返回的就是我们指定的请求方式public String getMethod() {return this.method;}}
}
@RequestMapping(value = "/employee/{id}", method = RequestMethod.DELETE)
public String deleteEmployee(@PathVariable("id") Integer id){// 根据Id删除对于的员工employeeDao.delete(id);// 删除完员工后需要重定向到查询所有员工功能的请求,因为员工数据有变化需要重新查询并渲染// 重定向的目的就是为了刷新地址栏,防止用户一直刷新添加员工的请求return "redirect:/employee";
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/152483.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

突发!该国教育部将MDPI、Hindawi和Frontiers三大出版商打包“拉黑”了!

最近&#xff0c;基于对学术诚信和作者署名的特别关切&#xff0c;马来西亚大学教育部发布了一项声明&#xff0c;禁止该国的公立大学使用政府预算来支付在MDPI、Hindawi和Frontiers三家学术出版商旗下的所有期刊上发表论文的费用。 马来西亚大学教育部还成立了一个特别委员会…

Java注解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、在编译时进行格式检查&#xff08;JDK内置的三个基本注解&#xff09;二、使用步骤1.理解Annotation2.Annocation的使用示例3.如何自定义注解4.jdk 提供的4种元…

如何更好的使用结构化工艺文件编制软件?——青创智通

青创智通结构化工艺文件编制软件包括文件创建、文件编制、文件修改、文件复制、文件引用、标准文件库、工艺路线、工艺资源库管理、审批管理、文件导出、文件清单汇总、接口管理等功能。具有以下优势及亮点。 1.集中工艺数据管理 以PLM系统平台为核心的结构化工艺数据支撑平台…

Android 源码解析: SharedPreferences的解析

Android源码解析&#xff1a;SharedPreferences的解析 导言 SharedPreferences是Android中的一种轻量的数据持久化手段&#xff0c;可能也是我们在学习Android时接触到的第一种特殊的本地数据持久化手段&#xff0c;本篇文章就将从源码角度分析SharedPreferences的原理。 源…

android 修改输出apk的包名

一&#xff0c;打包方式使用IDE菜单选项 二、在app级别的build.gradle下配置&#xff1a; static def releaseTime() {return new Date().format("yyyyMMdd.kkmm", TimeZone.getTimeZone("GMT8")) }android.applicationVariants.all { variant ->print…

怎么压缩pdf文件?分享缩小pdf文件的简单方法

在我们的日常生活和工作中&#xff0c;往往需要处理大量的PDF文件&#xff0c;而很多时候这些文件的大小会成为传输和存储的难题。为了解决这个问题&#xff0c;下面我们将介绍三种方法来压缩PDF文件&#xff0c;一起来看看吧~ 一、嗨格式压缩大师 首先&#xff0c;最简单也是…

CSS 实现:常见布局

1 设备与视口 设备屏幕尺寸是指屏幕的对角线长度。像素是计算机屏幕能显示一种特定颜色的最小区域&#xff0c;分为设备像素和逻辑像素。 在 Apple 的视网膜屏&#xff08;Retina&#xff09;中&#xff0c;默认每 4 个设备像素为一组&#xff0c;渲染出普通屏幕中一个像素显示…

buuctf-[BSidesCF 2020]Had a bad day 文件包含

打开环境 就两个按钮&#xff0c;随便按按 url变了 还有 像文件包含&#xff0c;使用php伪协议读取一下&#xff0c;但是发现报错&#xff0c;而且有两个.php,可能是自己会加上php后缀 所以把后缀去掉 /index.php?categoryphp://filter/convert.base64-encode/resourcei…

【APP】上架指南:iOS App Store 首次上架被拒原因分析与解决方案

目录 一、前言 二、APP 审核备案新规 &#xff08;1&#xff09;iOS 上架审核申请被拒 &#xff08;2&#xff09;苹果应用商店重大调整 &#xff08;3&#xff09;首次备案流程 ① 阿里云备案 ② 华为云备案 ③ 腾讯云备案 三、iOS 首次上架拒审原因分析 &#…

[羊城杯 2020]easyser - 反序列化+SSRF+伪协议(绕过死亡die)

[羊城杯 2020]easyser 一、解题过程&#xff08;一&#xff09;、一阶段&#xff08;二&#xff09;、二阶段 二、思考总结 一、解题过程 &#xff08;一&#xff09;、一阶段 可以直接使用ctf-wscan扫描一下有什么文件&#xff0c;或者直接试试robots.txt能不能行 直接打开…

【算法训练-数组 三】【数组矩阵】螺旋矩阵、旋转图像、搜索二维矩阵

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是螺旋矩阵&#xff0c;使用【二维数组】这个基本的数据结构来实现 螺旋矩阵【EASY】 二维数组的结构特性入手 题干 解题思路 根据题目示例 mat…

用《斗破苍穹》的视角打开C#3 标签与反射(人物创建与斗技使用)

随着剧情的发展&#xff0c;主线人物登场得越来越多&#xff0c;时不时跳出一个大佬&#xff0c;对我张牙舞爪地攻击。眼花缭乱的斗技让我不厌其烦&#xff0c;一个不小心&#xff0c;我就记不清楚在哪里遇上过什么人&#xff0c;他会什么斗技了。这时候&#xff0c;我就特别希…

通过IP地址管理提升企业网络安全防御

在今天的数字时代&#xff0c;企业面临着越来越多的网络安全威胁。这些威胁可能来自各种来源&#xff0c;包括恶意软件、网络攻击和数据泄露。为了提高网络安全防御&#xff0c;企业需要采取一系列措施&#xff0c;其中IP地址管理是一个重要的方面 1. IP地址的基础知识 首先&a…

华为数通方向HCIP-DataCom H12-831题库(单选题:221-240)

第221题 以下哪些项能被正则表达式^30.成功匹配? A、200 100 300 B、100 200 300 C、300 200 100 D、300 100 200 答案:CD 解析: 30.其中的“点”表示的是任何的一个数字,表示的是as-path的开头;所以以300开头的都是满足题目需求的。 第222题 以下哪些项的Community属性能…

安卓 Android 终端接入阿里云 IoT 物联网平台

在全球智能手机市场里&#xff0c;谷歌开发的安卓(Android)移动操作系统市场占有率已经高达90%。随着物联网智能硬件升级&#xff0c;安卓(Android)也逐渐成为智能摄像头&#xff0c;智能对讲门禁&#xff0c;人脸识别闸机&#xff0c;智能电视&#xff0c;智能广告屏等带屏 Io…

Android多线程学习:线程

一、概念 进程&#xff1a;系统资源分配的基本单位&#xff0c;进程之间相互独立&#xff0c;不能直接访问其他进程的地址空间。 线程&#xff1a;CPU调度的基本单位&#xff0c;线程之间共享所在进程的资源&#xff0c;包括共享内存&#xff0c;公有数据&#xff0c;全局变量…

Java虚拟机内存模型

JVM虚拟机将内存数据分为&#xff1a; 程序计数器、虚拟机栈、本地方法栈、Java堆、方法区等部分。 程序计数器用于存放下一条运行的指令&#xff1b; 虚拟机栈和本地方法栈用于存放函数调用堆栈信息&#xff1b; Java堆用于存放Java程序运行时所需的对象等数据&#xff1b…

webpack不同环境下使用CSS分离插件mini-css-extract-plugin

1.背景描述 使用mini-css-extract-plugin插件来打包css文件&#xff08;从css文件中提取css代码到单独的文件中&#xff0c;对css代码进行代码压缩等&#xff09;。 本次采用三个配置文件&#xff1a; 公共配置文件&#xff1a;webpack.common.jsdev开发环境配置文件&#x…

接口测试及常用接口测试工具

首先&#xff0c;什么是接口呢&#xff1f; 接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口&#xff1a;比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你…

maven 初学

1. maven 安装 配置安装 路径 maven 下载位置: D:\software\apache-maven-3.8.6 默认仓库位置: C:\Users\star-dream\.m2\repository 【已更改】 本地仓库设置为&#xff1a;D:\software\apache-maven-3.8.6\.m2\repository 镜像已更改为阿里云中央镜像仓库 <mirrors>…