SpringMVC学习笔记

SpringMVC概述

1. SpringMVC概念

SpringMVC是Spring3.0发布以后内置的一个MVC框架,解决WEB开发过中常见的问题,与SPring无缝集成,支持RESTful风格的URL请求,采用松散耦合可插拔组件结构,比其他MVC框架更具扩展性和灵活性。

2. SpringMVC原理

SpringMVC就是对Servlet进行深层次的封装

3. 优势

基于MVC分工明确、轻量级、能够使用Spring的Ioc和AOP、方便整合其他优秀框架

4. MVC模式回顾

Model:模型层 javaBean、数据访问和业务处理 dao service pojo

View:视图 JSP技术,负责展示数据

Controller:控制器 servlet技术 中间调度

控制器的工作:1.接收客户端的请求 2.调用模型层中的业务逻辑处理 3.页面导航

5.实例

  1. 创建maven工程,补齐目录结构
image-20210915161036484
  1. 添加依赖 SpringMVC、Servlet
image-20210915165512892
  1. 创建Spring和SpringMVC配置文件,添加包扫描,SpringMVC注解驱动,视图解析器,静态文件处理器…
  • SpringMVC配置文件
image-20210915173430546
  1. 在web.xml中进行Spring和SpringMVC配置
image-20210915171401670
  1. 创建控制器
image-20210915173752887
  1. 创建jsp页面
image-20210915173908143
  1. 测试
image-20210915174144142

SpringMVC工作流程

SpringMVC工作流程图
image-20210915180604403
  1. 用户通过浏览器发送请求到前端处理器DispatcherServlet
  2. 前端处理器直接将请求转发给处理器映射器HandleMapping
  3. 处理器映射器会根据请求, 找到负责处理器该请求的处理器, 并将其封装为处理器执行链handerExecutionChain返回给前端控制器
  4. 前端处理器会根据处理器执行链找到对应的处理器适配器HandleAdaptor
  5. 处理器适配器调用执行处理器Controller
  6. 处理器将处理结果和要跳转的视图封装到ModelAndView对象中返回
  7. 适配器将ModleAndView返回给前端控制器
  8. 前端控制器将ModelAndView传给视图解析器ViewResolve
  9. 视图解析器根据视图名称封装为视图对象View返回
  10. 前端控制器调用视图对象让其进行渲染
  11. 视图对象将渲染结果返回
  12. 前端控制器响应给客户浏览器

SpringMVC组件

**DispatcherServlet: ** 前端控制器, 中央空控制器, 用户请求的入口控制器, 它的存在降低了组件之间的耦合性.

**HandleMapping: ** 处理器映射器, 负责根据用户请求找到处理器Controller, SpringMVC提供了不同的映射器映射方式, 例如: 配置文件方式, 实现接口方式, 注解方式 (实际开发中最常用)

**Handler(Controller): ** 具体的用户请求处理器, 涉及到业务请求, 程序员根据业务需求开发

**HandleAdaptor: ** 处理器适配器, 适配器的应用, 可通过扩展处理器适配器, 支持更多类型的处理器

**ViewResolver: ** 视图解析器, 根据逻辑视图名解析成物理视图路径, 封装为View视图对象, 视图类型包括: jstlView、freemarkerView、pdfView 等.


@RequestMapping注解

注解使用规则

image-20210915185327077

ElementType.TYPE 和 ElementType.METHOD 指定该注解可定义类上, 也可以定义在方法上, 定义在类上表示全局路径, 定义在方法上表示具体的路径

image-20210916005232965

测试

image-20210917005116172

常用的提交方式

请求方式提交方式
地址栏请求get请求
超链接请求get请求
表单请求默认get, 可以指定post
AJAX请求默认get, 可以指定post

DispatcherServlet的url-pattern解析

web.xml中配置SpringMVC地址解析中一般有两种写法

  1. *.do 没有特殊要求的请情况下, DispatcherServlet一般常使用的后缀

  2. / (推荐这么写, 在使用地址栏传值时必须这么写) , 可以写成/, 但在静态资源请求时DispatcherSerlvet会当成一个普通的Controller请求, 前端控制器会调用处理器映射器查找响应的处理器, 当然找不到, 会报404错误, 因此必须在springmvc.xml中配置静态资源处理器, 两种方法:

    image-20210916011205039

处理器方法的参数

1. 参数名称匹配接收

参数的名称要和前端请求的参数name保持一致, 数值类型可以自动转换

(若不一致匹配失败, 则以null进行参数填充)

前端提交表单:

image-20210916193545292

后端处理器:

image-20210916194911723

2. 接收日期类型的参数

日期类型的参数需添加@DateTimeFormat注解进行转换

(若转错误会报400错误)

前端请求

image-20210916195649605

后端处理器

image-20210916195759567

3. 使用对象接收参数

接收对象
的属性名称要和请求的参数名称name保持一致

(若不一致匹配失败, 则以null进行参数填充)

POJO实体对象

image-20210916195102341

后端处理器

image-20210916194744247

前端请求

image-20210916195124083

4. 矫正参数名称

通过注解@RequestParam进行矫正, value属性填入矫正后的名称

required属性填true(默认),矫正失败会报400错误 , required属性填false, 矫正失败不报错, 以null填充参数

前端请求

image-20210916201237186

后端处理

image-20210916201718521

5. 通过URL地址传参

URL地址传参需要@RequestMapping中的value属性使用/{name}进行匹配

URL可以匹配多个地址

@PathVariable

  • value属性与@RequestMapping中括号名称一致
  • required属性为true(默认): 表示必须匹配此参数, 没有则报500错 false: 非必须匹配, 没有则用null填充

URL匹配参数失败, 报404错

前端请求

image-20210916204916500

后端处理器

image-20210916220148951

6. 使用原生HttpServletRequest

接收单个参数用getParameter()方法

接收数组用getParameterValues()方法

7. 接收数组类型参数

1. 通过匹配参数名称

2. 通过原生HttpServletRequest

前端请求

image-20210916234320142

后端处理器

image-20210916234648234

8. 接收集合类型参数

1. 简单集合类型通过@RequestParam注解绑定

2. 自定义对象的集合类型不支持直接获取, 必须封装到一个类中, 作为一个属性操作

前端请求

image-20210917000519852

POJO实体类

image-20210917000549830

封装的中间VO对象

image-20210917000657486

后端处理器

image-20210917001240572

乱码解决方案

SpringMVC中有同意字符集的过滤器对象CharacterEncodingFilter, 在web.xml中配置过滤器filter

image-20210917002631648

源码解析

  1. 如果设置了encoding, 没有强制request或者response使用, 则使用自行设置的encoding
  2. 如果设置了encoding, 并且强制request或者response使用, 则自行设置的encoding失效, 使用web.xml中配置的encoding
image-20210917003812017

在静态资源请求中存在乱码问题

  1. 若使用Web应用服务器的默认处理器可能会出现乱码, 因此尽量改为Spring专用的静态资源处理器<mvc:resource>

  2. 过滤器的url-pattern明确指明过滤的路径, 排除静态html路径即可避免


处理方法的返回值

1. 返回ModelAndView

// 返回ModelAndView类型
@RequestMapping("modelandview")
public ModelAndView modelAndView(){
    ModelAndView modelAndView = new ModelAndView();
    // 跳转页面
    modelAndView.setViewName("result/index");
    // 携带数据
    modelAndView.addObject("result", new Result(200, "经过ModelAndView返回", null));
    return modelAndView;
}

如果是前后端不分的开发, 大部分情况下, 使用ModelAndView, 既有数据的携带还有资源的跳转

如果只是需要传递数据或者跳转之一, ModelAndView并不是最好的选择

2. 返回String

视图解析器会将要跳转的视图名称转换为物理路径

视图解析器

image-20210917014013847
// 返回字符串类型
@RequestMapping("string")
public String string(HttpServletRequest request){
    Result result = new Result(200, "经过String返回", null);
    // 携带数据
    request.setAttribute("result", result);
    // 跳转页面,视图解析器会解析为: /result/index.jsp
    return "result/index";
}

3. 返回对象类型

1. 当处理器返回Object对象时, 仅作为数据返回展示, 不进行视图跳转, 一般前端发起Ajax使用

2. 返回对象的时候, 需要使用@ResponseBody注解, 将转换后的JSON数据放入到响应体中

pom.xml中添加两个依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.8</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.9.8</version>
</dependency>

前端ajax请求

image-20210917133723379

后端处理器

// 返回对象类型, 不进行页面跳转
@ResponseBody
@RequestMapping("obj")
public Object obj(){
    Result result = new Result(200, "经过Object返回", null);
    // 直接返回数据
    return result;
}

void返回值

void不是没有返回数据, 是通过HttpServletRequest, sevlet中的处理方案


导航页面

页面的导航分为两种: 1. 转发 2. 重定向

  • 转发: forward: url (默认)

  • 重定向: redirect: url

    重定向需要注意一点, 传递的参数只能是简单数据类型

    • Spring重定向, request保存的参数会丢失
    • ModelAndView重定向, ModelAndView中的参数会以URL携带参数的方式传递

转发一个页面

字符串方式转发

@RequestMapping("forwardstring")
public String string(HttpServletRequest request){
    Result result = new Result(200, "通过String转发", null);
    request.setAttribute("nav", result);
    return "forward:/jsp/nav/index.jsp";
}

ModelAndView方式转发

@RequestMapping("forwardmodelandview")
public ModelAndView modelAndView(){
    ModelAndView modelAndView = new ModelAndView();
    Result result = new Result(200, "通过ModelAndView转发", null);
    modelAndView.addObject("nav", result);
    modelAndView.setViewName("forward:/jsp/nav/index.jsp");
    return modelAndView;
}

重定向一个页面

字符方式重定向

@RequestMapping("redirectstring")
public String redirectstring(HttpServletRequest request){
    request.setAttribute("nav", "通过String重定向");
    return "redirect:/jsp/nav/index.jsp";
}

ModelAndView方式重定向

@RequestMapping("redirectmodelandview")
public ModelAndView redirectmodelandview(){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("nav", "通过ModelAndView转重定向");
    modelAndView.setViewName("redirect:/jsp/nav/index.jsp");
    return modelAndView;
}

重定向或者转发到控制器

1. ModelAndView转发到处理器, 通过request直接传参

2. Spring转发到处理器, 通过request直接传参

3. ModelAndView重定向处理器, 通过request直接传参, 但只能传字符串

// ModelAndView转发到处理器, 通过request直接传参
@RequestMapping("forwardtohandle")
public ModelAndView forwardtohandle(){
    ModelAndView modelAndView = new ModelAndView();
    Result result = new Result(200, "通过ModelAndView转发到处理器", null);
    modelAndView.addObject("nav", result);
    modelAndView.setViewName("forward:/nav/converge");
    return modelAndView;
}

// Spring转发到处理器, 通过request直接传参
@RequestMapping("forwardtohandle2")
public String forwardtohandle2(HttpServletRequest request){
    Result result = new Result(200, "通过ModelAndView转发到处理器2", null);
    request.setAttribute("nav", result);
    return "forward:/nav/converge";
}

// ModelAndView重定向到处理器, 通过request直接传参, 但只能传字符串
@RequestMapping("redirecttohandle")
public ModelAndView redirecttohandle(){
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("nav", "通过ModelAndView重定向到处理器,参数只能是字符串");
    modelAndView.setViewName("redirect:/nav/converge");
    return modelAndView;
}


@RequestMapping("converge")
public String converge(HttpServletRequest request){
    // 接收转发参数
    System.out.println("request: " + request.getAttribute("nav"));
    // 接收重定向参数
    String nav2 = request.getParameter("nav");
    System.out.println("request param: " + nav2.toString());
    if(nav2 != null)
        request.setAttribute("nav", nav2);
    return "forward:/jsp/nav/index.jsp";
}

异常处理

@ExceptionHandler注解

@ExceptionHandler注解是将一个方法指定为异常处理方法

被注解的方法也是一个处理器Controller, 方法的参数可以是Exception及其子类对象, 系统会自动为这些方法参数赋值

@ControllerAdvice

增强Controller, 可实现全局异常捕获处理

@ControllerAdvice
public class MyGlobalExceptionHandle {
    @ExceptionHandler(value = {Exception.class})
    public ModelAndView globalExceptions(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("myerr");
        return mv;
    }
}

自定义异常

自定义异常包, 类

image-20210917181252785

抛出自定义异常

// 全局异常
@RequestMapping("err")
public String err(Integer num){
    System.out.println(1/num);
    return "err/ok";
}

// 自定义id异常
@RequestMapping("iderr")
public String iderr(Integer id) throws IdErr {
    if(id < 10)
        throw new IdErr("id不能小于10");
    return "err/ok";
}

// 自定义name异常
@RequestMapping("nameerr")
public String nameerr(String name) throws IdErr, NameErr {
    if("".equals(name))
        throw new NameErr("name不能为空串");
    return "err/ok";
}

异常处理器

@ControllerAdvice
public class MyGlobalExceptionHandle {
    @ExceptionHandler(value = {Exception.class})
    public ModelAndView globalExceptions(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("err/err");
        return mv;
    }

    @ExceptionHandler(value = {IdErr.class})
    public ModelAndView idErr(IdErr e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("err/err");
        return mv;
    }

    @ExceptionHandler(value = {NameErr.class})
    public ModelAndView nameErr(NameErr e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("message", e.getMessage());
        mv.setViewName("err/err");
        return mv;
    }
}

拦截器

SpringMVC中的拦截器主要作用就是拦截用户请求, 进行相应的预处理和后处理

三种方法的执行时间

image-20210917191909533

preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

  • 执行时间: 在Controller执行前拦截, 若返回true继续执行Controller, 返回false则不执行后续
  • 使用场景: 登陆验证

postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)

  • 执行时间: 在Controller执行之后, 可修改ModelAndView
  • 使用场景: 日志记录, 登陆IP记录, 时间记录

afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)

  • 执行时间: View视图已经渲染完成之后, 修改ModelAndView无效
  • 使用场景: 全局资源的操作, 清除资源等

注: 存在多个拦截器时, 预处理顺序, 后处理逆序

创建拦截器

实现接口 HandlerInterceptor

重写三个方法

image-20210917193215737

springmvc.xml中进行拦截器配置

mapping: 匹配要拦截的路径, 最后为**

bean: 指定执行的拦截器

<!-- 拦截器配置 -->
<mvc:interceptors>
    <mvc:interceptor>
        <!-- 拦截器要拦截的路径 -->
        <mvc:mapping path="/**"/>
        <!-- 指定执行的拦截器 -->
        <bean class="com.jumaojiang.interceptor.MyInterceptor2"/>
    </mvc:interceptor>
    <mvc:interceptor>
        <!-- 拦截器要拦截的路径 -->
        <mvc:mapping path="/**"/>
        <!-- 指定执行的拦截器 -->
        <bean class="com.jumaojiang.interceptor.MyInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

文件上传下载

SpringMVC为文件上传提供直接支持, 通过MultipartResolver, 实现类CommonsMultipartResolver

实例步骤

文件上传

  1. 添加依赖
<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
  1. springmvc.xml中配置MultipartResolver

注: id一定要填multipartResolver

<!-- 文件传输处理配置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
  1. 前端表单提交

注: 1. 类型enctype=“multipart/form-data” 2. method="post"

image-20210917203630326
  1. 创建后端文件上传处理器
  1. UUID.randomUUID()方法获取随机值给文件重命名(一开发都需要, 避免冲突)
  2. request.getServletContext().getRealPath("/uploadFile")创建存储路径在项目运行的web容器下
  3. file.transferTo()存储文件
@RequestMapping("upload")
public String upload(HttpServletRequest request, MultipartFile file) throws IOException {
    // 封装了随机uuid生成工具, 实际开发中一般都需要给文件重命名以避免文件名冲突
    String reName = FileRenameUtil.fileRename(file);
    // 创建存储路径
    String realPath = request.getServletContext().getRealPath("/uploadFile");
    File path = new File(realPath);
    if(!path.exists())
        path.mkdir();
    // 存储文件
    file.transferTo(new File(path,reName));
    System.out.println("上传成功: " + realPath + "/" + reName);
    request.setAttribute("file", realPath + "/" + reName);
    return "file/index";
}

文件下载

  1. 前端表单提交

enctype=“multipart/form-data” method="post"

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHB6Ez3r-1631961564520)(…/AppData/Roaming/Typora/typora-user-images/image-20210917204359970.png)]

  1. 后端处理器
  • 创建响应头信息
  • 标记以流的方式做出响应
  • 以附件的形式响应给用户
  • 响应数据
@ResponseBody
@RequestMapping("download")
public ResponseEntity<byte[]> download(HttpServletRequest request) throws Exception {
    // 指定文件的路径
    String file = request.getParameter("file");
    if(! new File(file).exists())
        throw new Exception("指定路径的文件不存在");
    // 创建响应头信息对象
    HttpHeaders httpHeaders = new HttpHeaders();
    // 标记以流的方式做出响应
    httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    // 以附件的形式响应给用户
    String fileName = URLEncoder.encode(file.substring(file.lastIndexOf("/") + 1), "utf-8");
    httpHeaders.setContentDispositionFormData("attachment", fileName);
    // 响应数据
    File file1 = new File(file);
    ResponseEntity<byte[]> responseEntity =
            new ResponseEntity<>(FileUtils.readFileToByteArray(file1), httpHeaders, HttpStatus.CREATED);
    return responseEntity;
}

限定文件的类型和大小

限定文件的类型

创建文件类型拦截器

  1. 判断请求是否是文件上传
  2. 遍历所有上传文件
  3. 判断是否是允许上传类型之一, 不存则则抛出异常
image-20210917223007535

springmvc.xml配置拦截器

<mvc:interceptor>
    <mvc:mapping path="/file/**"/>
    <bean class="com.jumaojiang.interceptor.FileInterceptor"></bean>
</mvc:interceptor>

限定文件大小

springmvc.xml中配置MultipartResolver

<!-- 文件传输处理配置 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 文件上传大小限制, 以字节B为单位 : 5M = 5*1024*1024B = 5242880 B -->
    <property name="maxUploadSize" value="5242880"/>
    <property name="defaultEncoding" value="utf-8"/>
</bean>

RESTful风格

REST(Representational State Transfer, 简称REST)

它是一种软件架构风格, 设计风格, 提供了一组设计原则和约束条件

使用RESTful操作资源:

GET /expresses	  		#查询所有的快递信息列表
GET /express/1006		#查询一个快递信息
POST /express			#新建一个快递信息
PUT /express/1006		#更新一个快递信息(全部更新)
PATCH /express/1006		#更新一个快递信息(部分更新)
DELETE /express/1006	#删除一个快递信息

API设计/URL设计

RESTful的核心思想就是客户端的用户发出的数据操作指令都是"动词 + 宾语" (一眼看到请求的参数就大致知道需要做什么)

1.根据 HTTP 规范, 动词一律大写

2.一些代理只支持POST和GET方法, 为了使用这些有限的方法支持RESTful API, 需要一种办法覆盖原来的方法. 使用定制的HTTP头 X-HTTP-Method-Override来覆盖POST方法

  • 宾语就是API的URL, 应该只能是名词, 不能包含动词
  • 比如/expresses这个URL是正确的 /getExpress包含了动词, 不推荐

避免多级URL

例如: 查询所有还未取出的快递:

GET /expresses/statu/false	#不推荐
GET /expresses?statu=false  #推荐

HTTP状态码

客户端每发出一次响应, 都会返回HTTP状态码数据

状态码三位数, 分成五个类别

五类状态码分别如下:
	1xx: 相关信息 (API不需要,直接忽略)
	2xx: 操作成功
	3xx: 资源重定向
	4xx: 客户端错误
	5xx: 服务器错误

2xx状态码

GET: 200 OK			#表示一切正常
POST: 201 Created	#表示新的资源已经成功创建
PUT: 200 OK
PATCH: 200 OK
DELETE: 204 No Content #表示资源已经成功删除

3xx状态码

API用不到301状态码(永久重定向)和302,307状态码(都表示暂时重定向), API级别可以不考虑这两种情况

API用到的3xx状态码主要有: 303 See Other表示参考另一个URL, 用于POST PUT DELETE请求, 收到303以后, 浏览器不会自动跳转, 而会上用户自己决定下一步怎么办

#只需要关注304状态码就可以了
304: Not Modified #客户端使用缓存数据

4xx状态码

400 Bad Request: 服务器不理解客户端的请求, 未做任何处理
401 Unauthorized: 用户未提供身份验证凭据, 或者没有通过身份验证
403 Forbidden: 用户通过了身份验证, 但是不具有访问资源所需的权限
405 Method Not Allowed: 用户已经通过身份验证, 但是所用的HTTP方法不在他的权限之内
410 Gone: 所请求的资源已从这个地址转移, 不再可用
415 Unsupported Media Type: 客户端要求的返回格式不支持. 比如, API 只能返回JSON格式, 但是客户端要求返回XML格式
422 Unprocessable Entity: 客户端上传的福建无法处理, 导致请求失败
429 Too Many Requests: 客户端的请求次数超过限额

5xx状态码

表示服务器端错误, 一般来说, API不会向用户透露服务器的详细信息, 所以状态码只要两个就够了

500 Internal Server Error: 客户的短请求有效, 服务器处理时发生了意外
503 Service Unavailable: 服务器无法处理请求, 一般用于网站维护状态

服务器响应

服务器返回的信息建议选择JSON对象, 这样才能返回标准的结构数据

  • 服务器回应的HTTP头的Content-Type属性要设为appliation/json
  • 客户端请求时, 也要明确告诉服务器可以接收JSON格式, 请求的HTTP头的ACCEPT属性也要设成application/json
  • 当发生错误的时候, 除了返回状态码之外, 也要返回错误信息, 所以要自己封装要返回的信息

封装响应结果

public class AjaxResultVo<T> {
    private Integer code;   // 返回的状态码
    private String msg;     // 返回的信息(一般是错误信息或异常信息)
    private Object obj;     // 返回的数据可能是对象
    private List<T> list;   // 返回的数据可能是集合

    public AjaxResultVo() {
        this.code = 200;
        this.msg = "ok";
        this.obj = null;
        this.list = null;
    }

    public AjaxResultVo(Integer code, String msg) {...}

    public AjaxResultVo(Integer code, String msg, List<T> list) {...}

    public AjaxResultVo(Integer code, String msg, Object obj) {...}
    
    // 省略get set方法
    ...
}

RESTful风格的更新和删除问题

问题:

在Ajax中,采用Restful风格PUT, PATCH和DELETE请求传递参数无效, 传递到后台的参数值为null

产生的原因:

Tomcat封装请求的过程:
	1.将请求体中的数据封装的成map
	2.request.getParameter(key)会从map中取值
	3.SpringMVC会从request.getParamter()中取值
AJAX发送PUT, PATCH, DELETE请求时, Tomcat不会封装成map, 导致最终SpirngMVC拿不到值,为null

解决方案:

使用HiddenHttpMethodFilter将普通的post请求转换为指定的PUT, PATCH, DELETE请求

前端部分

  1. 使用POST类型
  2. 参数中添加_method属性, 赋值为PUT / PATCH / DELETE
image-20210918174118146

web.xml中配置过滤器filter

<filter>
    <filter-name>httpMethodFilter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>httpMethodFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值