SpringMVC学习指南(2)


系列文章目录

SpringMVC学习指南(1)

关注博主,学习后续知识

在这里插入图片描述

前言

提示:
     本博客的内容是在上篇博客SpringMVC学习指南(1)的基础上更新的,没有看过上一篇的同学请移步看完上一篇博客之后,再进行本篇博客的阅读.
     本篇博客的会用大量的代码实例带你快速掌握SpringMVC开发的几个基本且重要的注解。希望大家在看博客的同时,多动手敲,多调试,便能更好的学会SpringMVC。


一、RequestMapping注解

该注解有四个常用属性,分别是:

属性名类型含义
valuestring[]请求映射
methodRequestMethod[]请求方式
paramsstring[]请求参数
headerstring[]请求头

1.1 value属性

(1)含义

  • 指定请求映射路径,SpringMVC中一个方法处理一个请求。这里的这个请求映射路径就对应前端发起的某个请求。

(2)有两个作用:

  1. 标注在类上:为下面的方法设置了一个基准路径,即:类下的所有方法都会有一个前缀地址。
  2. 标注在方法上:对应一个请求路径。即,该方法要处理的是哪个请求。

(3)实例:

    在前端页面点击超链接,发起请求 /hello ,后端myFirstRequest()方法上标注了 @RequestMapping(value
= “/hello”) 注解,就表示该方法是用来处理 /hello 请求的。

    处理完成之后,方法会返回一个字符串 “success”,我们配置的视图解析器(InternalResourceViewResolver)会完成拼串操作,即:会转发到一个success.jsp页面。

<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<html>
<body>
<h1>首页</h1>
	<a href="hello">HelloWorld测试</a><hr>
</body>
</html>

    @RequestMapping(value = "/hello")
    public String myFirstRequest()
    {
        System.out.println("hello请求正在处理……");
        //视图解析器自动拼串,拿到它的前后缀。
        //转发到 /WEB-INF/pages/success.jsp 页面
        return "success";
    }

1.2 method属性

(1)含义

  • 限定请求方式(GET请求、POST请求),默认是都接收,不区分GET和POST。
  • 如果设置了method的值,就只支持设置的请求方式,如果以其他的方式发起的请求,浏览器就会报错 405-Method Not Allowed

(2)method的四个取值

  1. RequestMethod.GET
  2. RequestMethod.POST
  3. RequestMethod.DELETE
  4. RequestMethod.PUT
  • 这些请求方式有什么用呢?
    在后文中我们会使用RUST风格的URL,到时候就会使用不同的请求方式发起请求。同一个URL,它发起的请求方式不同,后端的处理方式就不同。

(3)实例

    当然,这里设置method方式为GET是多此一举的,要求前端发起的超链接请求本就是GET方式的,这里只是为了说明如何使用。

    @RequestMapping(value = "/hello",method = RequestMethod.GET)
    public String myFirstRequest()
    {
        System.out.println("请求正在处理…… success");
        return "success";
    }

1.3 params属性

(1)含义

  • 规定请求参数,请求路径中必须有参数,如:?username=1

  • params属性 和 header属性 支持简单的表达式。

    • param:表示请求必须包含名为 param 的参数
    • !param: 表示请求不能包含名为 param 的参数
    • param != value : 表示请求必须包含名为 param 的参数,但其值不能为value
  • eg:

    • params = {“username”} :表示发送请求必须带上一个名为username的参数,请求路径中必须有参数,如:/hello?username=1
    • params = {"!username"}:表示请求不能包含名为username的参数。
    • params = {“username=123”},请求中的参数username必须是123。
    • params = {"!username=123",“pws=321”},路径中参数之间使用 & 连接。

1.4 header属性

(1)含义

  • 规定请求头

(2)作用:

  • 限定哪些浏览器可以访问。
    • User-Agent:浏览器信息,可以规定哪些浏览器可以访问,哪些不可以访问

      • 谷歌浏览器的User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36
      • IE浏览器的User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 Edge/18.18362
    @RequestMapping(value = "/handle04",headers = {"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36"})
    public String handle04()
    {
        return "success";
    }

1.5 通配符

     RequestMapping的模糊匹配 Ant风格的URL,使用通配符

URL地址中可以以下四个写通配符

  • ?:能替代任意一个字符
  • *:能替代任意多个字符(包括0个字符),和一层路径
  • **: 能替代多层路径

注意:当模糊匹配和精确匹配同时存在时,精确匹配优先。

代码示例:

@Controller
public class RequestMappingTest {
    @RequestMapping("/antTest01")
    public String antTest01()
    {
        System.out.println("antTest01");

        return "success";
    }


    /**
     * 只要请求路径是 /antTest0 开头,只要最后一个字符不同。
     *  模糊和精确多个匹配的情况下,精确匹配优先
     * @return
     */
    @RequestMapping("/antTest0?")
    public String antTest02()
    {
        System.out.println("antTest02");
        return "success";
    }

    @RequestMapping("/antTest0*")
    public String antTest03()
    {
        System.out.println("antTest03");
        return "success";
    }
}

二、PathVariable 注解

    拿到请求路径中占位符的信息。

路径上可以有占位符:

  • 占位符的使用。语法:{变量名}
  • 占位符只能占一层路径

eg:

<a href="user/LXY">路径属性值测试</a><br/>
@RequestMapping("/user/{name}")
public String pathVariableTest(@PathVariable("name") String name)
{
    System.out.println("路径上的占位符的值为"+name);
    return "success";
}

三、REST风格的URL

3.1 REST简介

    REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用

  • 资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。要获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。

  • 表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。

  • 状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)。而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:(请求方式)

  1. GET 用来获取资源

  2. POST 用来新建资源

  3. PUT 用来更新资源

  4. DELETE 用来删除资源。

比如:

发送的请求是 “/book”:

  • 如果是以GET方法发送的,就认为是获得book。
  • 如果是以DELETE方式发送的,就认为是删除book。

通俗来说:
    REST风格是希望以非常简洁的URL地址来发送请求,用请求方式来区分对一个资源的增删改查。

3.2 REST风格URL的使用

(1)我们在JavaWeb中写的URL

  • /getBook?id=1 查询id为1的图书

  • /deleteBook?id=1 删除id为1的图书

(2)REST风格的URL

  • 格式: /资源名/资源标识符
  • eg:URL为:/book/1
    • GET:查询1号图书
    • PUT:更新1号图书
    • DELETE:删除1号图书

(3)存在的问题

页面只能发起GET和POST请求,其他方法的请求无法发起

  • 解决: Spring提供了REST风格的支持

    • SpringMVC有一个Filter,他可以把普通的请求转换为规定形式的请求。
      • 在web.xml 中配置Fitter。(HiddenHttpMethodFilter)
<!--  配置filter,将POST请求转换为其他合适的请求方式,如DELETE,PUT-->
  <filter>
    <filter-name>filter</filter-name>
    <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>filter</filter-name>
<!-- 过滤所有请求,只有Servlet中写的是“/”,其他地方的url写的还是“/*”-->
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  • 如何发起其他形式的请求?
    1. 创建一个POST类型的表单
    2. 表单项(input标签)中携带一个_method 的参数。
    3. 这个 _method 的值(value)就是DELETE或者PUT
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<html>
<body>
<h2>图书的增删改查,使用REST风格的URL地址</h2>

<a href="book/1">查询图书</a>

<form action="book" method="post">
    <input type="submit" value="保存图书">
</form>

<%--Delete请求--%>
<form action="book/1" method="post">
    <input name="_method" value="DELETE">
    <input type="submit" value="删除图书">
</form>

<%--Put请求--%>
<form action="book/1" method="post">
    <input name="_method" value="PUT">
    <input type="submit" value="更新图书">
</form>

</body>
</html>
@Controller
public class BookController {
    @RequestMapping(value = "/book",method = RequestMethod.POST)
    public String addBook()
    {
        System.out.println("添加图书成功");
        return "success";
    }

    @RequestMapping(value = "/book/{bookId}",method = RequestMethod.DELETE)
    public String deleteBook(@PathVariable("bookId") Integer id)
    {
        System.out.println("已经删除了【 "+id+" 】号图书");
        return "success";
    }

    @RequestMapping(value = "/book/{bookId}",method = RequestMethod.PUT)
    public String updateBook(@PathVariable("bookId") Integer id)
    {
        System.out.println("已经更新了【 "+id+" 】号图书");
        return "success";
    }

    @RequestMapping(value = "/book/{bookId}",method = RequestMethod.GET)
    public String getBook(@PathVariable("bookId") Integer id)
    {
        System.out.println("已经查询到了【 "+id+" 】号图书");
        return "success";
    }
}

3.3 HiddenHttpMethodFilter源码分析

(1)HiddenHttpMethodFilter的底层实现:

  1. 确定请求是POST。
  2. 从请求中拿到“_method”对应的value的值,并转换为大写。
  3. new出一个新的“HttpServlet对象”即:HttpMethodRequestWrapper,将新的method设置为其新的请求类型。
  4. 并放行这个新的“HttpServlet”对象。

HiddenHttpMethodFilter部分源码:

public static final String DEFAULT_METHOD_PARAM = "_method";

private String methodParam = DEFAULT_METHOD_PARAM;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
      throws ServletException, IOException {

   HttpServletRequest requestToUse = request;

   if ("POST".equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null) {
        //拿到_method 对应的值。
      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);
         }
      }
   }

   filterChain.doFilter(requestToUse, response);
}

(2)高版本的Tomcat可能会出现的问题

在上面的程序中可能会出现如下错误:

  • 原因:

    • 高版本的Tomcat对jsp页面有约束。Tomact 8.0之后
  • 解决:

    • 在需要跳转到的jsp页面中加上对异常的支持

上面的程序执行完毕之后是要跳转到 success.jsp 页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isErrorPage="true" %>
<html>
<head>
    <title>成功页面</title>
</head>
<body>
<h2>成功!!!</h2>
</body>
</html>

四、参数传入

问:什么叫参数传入?
答:参数传入,即:如何获取前端页面(表单等)提交的参数信息,并在后端处理方法中使用。

4.1 基本类型参数的获取

(1)默认方式

  • 默认方式获取请求参数,只需给方法参数上写一个和前度叶面参数名相同的变量,这个变量就自动来接收请求参数的值。
    • 有值:则直接获取
    • 无值:null

(2)使用注解

  • @RequestParam:获取表单中提交的参数

  • 该注解相当于原生Servlet中的:request.getParameter(key)

  • eg:

public String test01(@RequestParam(value = "username",required = false,defaultValue = "Hello") String name)
{
}

相当于:name=request.getParameter("username);

  • 注意:如果直接使用该注解,则默认请求中必须带要获取的参数名,不带就报错。可以使用注解的属性改变。

    • value:默认。获取指定key的参数
    • required:是否必须指定。布尔类型
    • defaultValue:默认值,原本默认是null,现在可以指定默认值
  • 注意和 @PathVariable的区别:

    • @PathVariable 是获取路径中的key对应的值
      • @PathVariable("user") 获取/book/{user}
      • @RequestParam("user") 获取前端提交的参数,例如:form表单中的user参数。

(3)扩展学习两个注解

@RequestHeader 和 @CookieValue

  • @RequestHeader: 获取请求头中的值。

    • 相当于:原生Servlet:request.getHeader("key");
    • 如果请求头中没有这个key,会报500错误。
    • 该注解也有valuerequireddefaultValue属性值,其使用方法和 @RequestParam 中的三个属性一样。
  • @CookieValue:获取某个cookie的值。

    • 相当于:原生Servlet:Cookies[] cookies = request.getCookies();,只不过原生Servlet中获取的是所有的cookie,然后在遍历拿到真正需要的那个cookie。
    • 该注解也有三个属性:required,defaultValue,defaultValue。同上。

看一段代码来熟悉一下这三个注解

前端页面

<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" isErrorPage="true"%>
<html>
<body>
<h2>测试获取请求参数</h2>
<a href="testParam?username=Tom">获取参数</a><br/>
<a href="testHeader">获取请求头信息</a><br/>
<a href="testCookies">获取Cookies信息</a><br/>

</body>
</html>

controller代码

package nuc;
/**
*  获取请求带来的参数
*/
@Controller
public class RequestParamsController {

    /**
     *
     * @return 成功页面

     */
    @RequestMapping(value = "/testParam")
    public String testRequest01(@RequestParam(value = "username",required = false,defaultValue = "Hello") String name)
    {
        System.out.println("请求参数:"+name);
        return "success";
    }


    @RequestMapping(value = "/testHeader")
    public String testRequest02(@RequestHeader("User-Agent") String userAgent)
    {
        System.out.println("请求头信息:"+userAgent);
        return "success";
    }
    @RequestMapping(value = "/testCookies")
    public String testRequest03(@CookieValue("JSESSIONID") String jsessionid)
    {
        System.out.println("Cookies 信息:"+jsessionid);
        return "success";
    }
}

4.2 自定义类型参数的获取

(1)概念

  • 如果我们方法的参数是一个实体类,SpringMVC会自动为这个实体类赋值。

    • 将这个实体类中的每一个属性(要求和前端页面提交的参数的名椅子),从request中获取出来,进行封装。

    • 还可以级联封装,即:这个实体类中还有另外一个实体类。(在请求中的参数也必须是级联的)

    • 注意:这个实体类的属性值的名要和请求中的参数名一致,否则会获取不到这个属性值,即为null。

(2)实践

前端页面:

<form action="addBook" method="post">
    书名:<input type="text" name="name">
    作者:<input type="text" name="author">
    价格:<input type="text" name="price">
    库存:<input type="text" name="stock">
    <hr/>
    <input type="text" name="address.province">
    <input type="text" name="address.city">//级联属性

    <input type="submit">
</form>

Book实体类

public class Book {
    private String bookname;
    private String author;
    private Double price;
    private int stock;
    private Address address;
}
@RequestMapping("/addBook")
public String addBook(Book book)
{
    System.out.println(book);
    return "success";
}

这个addBook() 方法中的book,就会和前端页面提交的参数进行一对一绑定。(前提是参数名一致)

五、中文乱码的解决

5.1 请求乱码

1. GET请求

     改Tomcat的server.xml文件,在如图位置8080后,加上:URIEncoding=“UTF-8” (我这里并没有修改web.xml文件,大家如果没有遇到过GET请求中文乱码的话,就不必修改此处)

2. POST请求

  • 在JavaWeb中的处理方式是,在第一次获取请求参数之前设置:response.setCharacterEncoding("UTF-8");
  • 在SpringMVC中有一个专门的过滤器,它专门用来处理字符乱码。CharacterEncodingFilter
  • 在SpringMVC的配置文件中配置该过滤器。
<!--配置一个过滤字符编码方法的Filter,来处理字符乱码-->
<!--该Filter必须在所有的Filter之前。否则不会有过滤效果-->
<filter>
  <filter-name>characterEncodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <!-- 设置POST请求编码方式。其实默认就是UTF-8。只不过我们可以使用init-param标签类设置-->
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
  <!--设置响应编码-->
  <init-param>
    <param-name>forceResponseEncoding</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>characterEncodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
  • 注意:该过滤器要直接写在“前端控制器”的Servlet之后,即:在其他所有的Filter之前,否则会报错!!!
  • 原因:因为在JavaWeb中我们就知道,在设置字符编码时,就要在第一次获取参数之前设置。所以,该过滤器就就必须在其他过滤器之前,否则无法起到很好的字符编码过滤,SpringMVC就会发出报错信息。

5.2 响应乱码

对响应乱码的处理非常简单,使用一行代码即可
response.setContentType("text/html;charset=utf-8");

六、使用原生API

这里“使用原生API”的意思就是,在SpringMVC的控制器方法参数列表中使用JavaWeb中的API。即:

  1. HttpServletResponse:
  2. HttpServletRequest:
  3. HttpSession:
    还有一些,只不过这三个是常用的,其他的都不常用。这里就不再赘述了

原生API的使用,我们在JavaWeb中已经很熟悉了,这里就直接用一段代码来复习一些。

什么?你竟然没有了解过Servlet?🤦‍♂️🤦‍♂️🤦‍♂️。
也不要紧,先关注一波博主,等我整理完SpringMVC的知识点,就开始上传Servlet的有关东西。

传送门【博主

@RequestMapping("/servletApi")
public String addAPI(HttpSession session, HttpServletRequest request)
{
    request.setAttribute("requestParam","我是Request中的参数");
    session.setAttribute("sessionParam","我是session中的参数");
    return "success";
}

在success.jsp 页面使用EL表达式获取我们放入原生API中的数据(前提是导入JSTL的包)

<html>
<head>
    <title>成功页面</title>
</head>
<body>
<h2>成功!!!</h2>
<hr>
Request参数:${requestScope.requestParam}
Session参数:${sessionScope.sessionParam}
</body>
</html>

在这里插入图片描述

移步博主首页

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值