【JavaEE进阶】——Spring Web MVC (请求)

目录

[🚩什么是Spring MVC](#🚩什么是Spring MVC)

🚩请求

🚩注解

🍭@RequestMapping路由映射

🍭请求

📝传递单个参数

📝传递多个参数

📝传递对象

📝后端参数重命名@RequestParam

📝传递数组

📝传递集合

📝传递JSON数据

📝获取URL中的参数

📝上传图片

📝获取Header

🍭Cookie和session机制

🎓理解Cookie

🎓理解Session

👩🏻‍💻获得cookie

👩🏻‍💻获得session


🚩什么是Spring MVC

官⽅对于 Spring MVC 的描述是这样的:
Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC", comes from the name of its source module (spring-webmvc)【Spring Web MVC是基于Servlet API的原始Web框架,从一开始就包含在Spring框架中。正式名称"Spring Web MVC"来自其源模块的名称(Spring -webmvc)。】
引⽤来⾃: https://docs.spring.io/spring-framework/reference/web/webmvc.html
从上述定义我们可以得出⼀个信息: Spring Web MVC 是⼀个 Web 框架.
下⾯咱们简称之为: Spring MVC


MVC是一种思想,Spring进行了实现,称为Spring MVC。SpringBoot是创建SpringMVC项目的一种方式而已。当前阶段,MVC概念由发生一些变化,后端开发人员不涉及前端页面的开发,所以也就没有view层,所以view又有一层解释,之前返回的是视图,现在返回的是视图所需要的数据。


我们在javaEE进阶的学习的时候,我们更多的是注重实践和练习,然后再进行理论知识的扶衬,更深刻的理解,所以我们首先初步的了解spring mvc是什么,它是一个Web框架,基于servlet实现的,剩下的我们在实践中理解。


🚩请求

访问不同的路径, 就是发送不同的请求. 在发送请求时, 可能会带⼀些参数, 所以学习Spring的请求, 主要 是学习如何传递参数到后端以及后端如何接收.
传递参数, 咱们主要是使⽤浏览器和Postman来模拟.
后端开发⼈员⽆需过度关注如何传递参数, 了解即可, 实际开发中以Postman测试为主.
⽐如餐厅的厨师, 不关注⽤⼾是在店⾥下单, 还是外卖平台下单, 或者⼩程序下单, 只需要知道如何接收订单, 根据订单做出对应的菜肴就可以了


🚩注解

🍭@RequestMapping路由映射

@RequestMapping可以修饰方法,也可以修饰类。访问地址:类的路径+方法路径

@RequestMapping("/hello")
@RestController
public class HellorController {
    @RequestMapping("/sayHi")
    //reuqestMapping可以接收get和post请求也可以delete任何请求
    public String sayHi(){
        return "hi,SpringBoot";
    }

    @RequestMapping("/sayhello")
    public String sayHello(){
        return "hello,SpringBoot";
    }
}

@RequestMapping支持get和post(可以用postman进行测试)我们要限制请求方式,使用method属性。

  //限制get请求
    @RequestMapping(value = "/sayHi/b",method = RequestMethod.GET)//只允许
    public String sayHi1(){
        return "hi,SpringBoot1";
    }

    //限制post请求
    @RequestMapping(value = "/sayHi/x",method = RequestMethod.POST)
    public String sayHi2(){
        return "hi,SpringBoot2";
    }

只限制post请求

只限制get请求


🍭请求

请求,主要就是学习如何传参

  • 传递单个参数
  • 多个参数
  • 对象
  • 数组/集合

在开发中,建议加上类路径,第一是避免重复,第二方便查找代码,否则我们在写另一个类中如果里面有相同的方法路径,我们是无法区分是哪个类的方法,所以我们建议是加上类路径。


📝传递单个参数

 //传递单个参数
    @RequestMapping("/m1")
    public String m1(String name){
        return "接收到的参数name:"+name;
    }

需要名称一样,底层逻辑:从请求的参数中,获取参数名为name的值,并给name赋值。


📝传递多个参数

  //传递多个参数
    @RequestMapping("/m2")
    public String m2(String name,Integer age){
        return "接收到的参数name:"+name+"接收到的参数age:"+age;
    }

需要注意的是,在开发时,建议使用包装类,使用基本类型的话,我们必须要在请求中传值,不传的话就会报错。比如Integer,是可以区分0和null的,而int的类型是不能区分null的。


📝传递对象

开发中,接口的参数通常定义为对象

因为我们上面传递多个参数和传递单个参数,其实都是可以放入一个集合类中进行封装,然后我们可以直接就传递对象。

  //传递对象
    @RequestMapping("/m3")
    public String m3(Person person){
        return "接收到的参数Person" +person;
    }


📝后端参数重命名@RequestParam

 //后端参数重命名  (必传参数)
    @RequestMapping("/m4")
    public String m4(@RequestParam("name")String username){
        return "接收到的参数name:"+username;
    }

发起请求中的参数是name,后端接收到的参数是username。

从请求的参数name重命名username,后端接收到的参数可以重命名为username。


    //如果前端没有发出请求中带有参数name,那么就会报400错误:400一般是客户端发出错误,400错误出现的原因主要是语义有误或请求参数有误,通常是由于客户端发送的请求格式不正确导致的
    @RequestMapping("/m5")
    public String m5(@RequestParam(value = "name",required = false)String username){
        return "接收到的参数name:"+username;
    }
    //后端接收响应的信息是username,但是前端发出的请求我想要是name,那么就重命名,这是必须传的参数


📝传递数组

当我们请求中,同一个参数有多个时,浏览器就会帮我们给封装成一个数组

    //传递数组
    @RequestMapping("/m6")
    public String m6(String[] arrayParam){
        return "接收到的参数arrayParam:"+ Arrays.toString(arrayParam)+",长度:"+arrayParam.length;
    }

📝传递集合

传递集合需要用到@RequestParam注解

    //传递集合
    @RequestMapping("/m7")
    public String m7(@RequestParam List<String> stringList){
        return "接收到的参数stringList:"+stringList+",长度"+stringList.size();
    }

📝传递JSON数据

JSON的语法:

    1. 数据在 键值对(Key/Value) 中
    1. 数据由逗号 , 分隔
    1. 对象⽤ {} 表⽰
    1. 数组⽤ [] 表⽰
    1. 值可以为对象, 也可以为数组, 数组中可以包含多个对象
      传递json数据,需要使用@RequestBody让json语言转成对象
 //传递json数据,需要使用@RequestBody让json语言转成对象
    @RequestMapping("/m8")
    public String m8(@RequestBody Person person){
        return "接收到的数据person:"+person.toString();
    }

📝获取URL中的参数

  //获取url中的参数  @PathVariable路径中获取参数
    @RequestMapping("/m9/{userId}")
    public String m9(@PathVariable Integer userId){
        return "userId:"+userId;
    }
    @RequestMapping("/mm9/{userId}/{name}")
    public String mm9(@PathVariable Integer userId,@PathVariable String name){
        return "userId:"+userId+",name:"+name;
    }


//方法路径中的url中的name和参数name需要相同
    @RequestMapping("/mmm9/{userId}/{name}")
    public String mmm9(@PathVariable Integer userId,@PathVariable("name") String username){
        return "userId:"+userId+",name:"+username;
    }

可以获取一个,也可以获取多个,但是需要注意他们的顺序,请求格式必须和后端定义的URL格式匹配 。


📝上传图片

   //上传图片
    @RequestMapping("/m10")
    public String m10(MultipartFile file) throws IOException {
        System.out.println(file.getOriginalFilename());
        file.transferTo(new File("D:/"+file.getOriginalFilename()));
        return "success";
    }

这个旨在D盘上上传一个文件


📝获取Header

头部信息获取,我们就拿user-agent来比例吧。

  • 第一种:通过原始的servlet进行获取User-Agent
  • 第二种:通过注解来获取
 //获取Header
    @RequestMapping("/getHeader")
    public String getHeader(HttpServletRequest request){
        String userAgent=request.getHeader("User-Agent");
        return "User-Agent:"+userAgent;
    }

    @RequestMapping("/getHeader2")
    public String getHeader2(@RequestHeader("User-Agent") String userAgent){
        return "User-Agent:"+userAgent;
    }

🍭Cookie和session机制

🎓理解Cookie

HTTP 协议⾃⾝是属于 "⽆状态" 协议.
"⽆状态" 的含义指的是:
默认情况下 HTTP 协议的客⼾端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆⽹站成功后, 第⼆次访问的时候服务器就能知道该请求是否是已经登陆过了.

上述图中的 "令牌" 通常就存储在 Cookie 字段中.
⽐如去医院挂号

    1. 看病之前先挂号. 挂号时候需要提供⾝份证号, 同时得到了⼀张 "就诊卡", 这个就诊卡就相当于患者的 "令牌".
    1. 后续去各个科室进⾏检查, 诊断, 开药等操作, 都不必再出⽰⾝份证了, 只要凭就诊卡即可识别出当前患者的⾝份.
    1. 看完病了之后, 不想要就诊卡了, 就可以注销这个卡. 此时患者的⾝份和就诊卡的关联就销毁了. (类似于⽹站的注销操作)
    1. ⼜来看病, 可以办⼀张新的就诊卡, 此时就得到了⼀个新的 "令牌"
      此时在服务器这边就需要 记录"令牌"信息, 以及令牌对应的⽤⼾信息, 这个就是 Session 机制 所做的⼯作。

🎓理解Session

我们先理解什么是会话。就相当于对话。

在计算机领域, 会话是⼀个客⼾与服务器之间的不中断的请求响应. 对客⼾的每个请求,服务器能够识别出请求来⾃于同⼀个客⼾. 当⼀个未知的客⼾向Web应⽤程序发送第⼀个请求时就开始了⼀个会话.当客⼾明确结束会话或服务器在⼀个时限内没有接受到客⼾的任何请求时,会话就结束了。
⽐如我们打客服电话
每次打客服电话, 是⼀个会话. 挂断电话, 会话就结束了
下次再打客服电话, ⼜是⼀个新的会话.
如果我们⻓时间不说话, 没有新的请求, 会话也会结束
服务器同⼀时刻收到的请求是很多的. 服务器需要清楚的区分每个请求是从属于哪个⽤⼾, 也就是属于哪个会话, 就需要在服务器这边记录每个会话以及与⽤⼾的信息的对应关系.
Session是服务器为了保存⽤⼾信息⽽创建的⼀个特殊的对象


Session的本质就是⼀个 "哈希表", 存储了⼀些键值对结构. Key 就是SessionID, Value 就是⽤⼾信息(⽤⼾信息可以根据需求灵活设计).

SessionId 是由服务器⽣成的⼀个 "唯⼀性字符串", 从 Session 机制的⻆度来看, 这个唯⼀性字符串称 为 "SessionId". 但是站在整个登录流程中看待, 也可以把这个唯⼀性字符串称为 "token".
上述例⼦中的令牌ID, 就可以看做是SessionId, 只不过令牌除了ID之外, 还会带⼀些其他信息, ⽐如时间, 签名等

    1. 当⽤⼾登陆的时候, 服务器在 Session 中新增⼀个新记录, 并把 sessionId返回给客⼾端. (通过HTTP 响应中的 Set-Cookie 字段返回).
    1. 客⼾端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId. (通过 HTTP 请求中的Cookie 字段带上).
    1. 服务器收到请求之后, 根据请求中的 sessionId在 Session 信息中获取到对应的⽤⼾信息, 再进⾏后续操作.找不到则重新创建Session, 并把SessionID返回

Cookie 和 Session 的区别

  • • Cookie 是客⼾端保存⽤⼾信息的⼀种机制. Session 是服务器端保存⽤⼾信息的⼀种机制.
  • • Cookie 和 Session之间主要是通过 SessionId 关联起来的, SessionId 是 Cookie 和 Session 之间的 桥梁
  • • Cookie 和 Session 经常会在⼀起配合使⽤. 但是不是必须配合.
  • ◦ 完全可以⽤ Cookie 来保存⼀些数据在客⼾端. 这些数据不⼀定是⽤⼾⾝份信息, 也不⼀定是SessionId
  • ◦ Session 中的sessionId 也不需要⾮得通过 Cookie/Set-Cookie 传递, ⽐如通过URL传递.

👩🏻‍💻获得cookie

遍历获取cookie的value和name

  • 第一种:通过原始的servlet中封装的HttpservletRequest

    @RequestMapping("/getCookie")
    public String getCookie(HttpServletRequest request){
    Cookie[] cookies=request.getCookies();
    // for (Cookie cookie : cookies) {
    // System.out.println(cookie.getName()+":"+cookie.getValue());
    // }
    if(cookies!=null){
    Arrays.stream(cookies).forEach(cookie -> {
    System.out.println(cookie.getName()+":"+cookie.getValue());
    });
    }
    return "获取cookie成功";
    }

此时获取cookie失败,我们知道cookie是客户端机制,我们可以手动的添加cookie。

此时cookie是不为空的,控制台打印出cookie存储的值。

  • 第二种:通过注解

    //使用注解拿到存储的cookie信息
    @RequestMapping("/getCookie2")
    public String getCookie2(@CookieValue String lisi){
    return "cookie存取的值lisi:"+lisi;
    }

存入lisi的name和value,后期通过注解拿到存储的cookie信息。

 //使用注解拿到存储的cookie信息
    @RequestMapping("/getCookie2")
    public String getCookie2(@CookieValue String lisi){
        return "cookie存取的值lisi:"+lisi;
    }

👩🏻‍💻获得session
  • 用servlet内置的HttpServletRequest 设置session(由于session是服务器机制)

    @RequestMapping("/setSession")
    public String setSession(HttpServletRequest request){
    HttpSession session=request.getSession();//一开始是没有的
    //我们就开始设置session
    session.setAttribute("username","zhangsan");//建立cookie
    return "success";
    }

  • 第一种:用servlet内置的HttpServletRequest进行发出请求设置cookie。

    @RequestMapping("getSession")
    public String getSession(HttpServletRequest request){
    HttpSession session=request.getSession(false);
    if(session!=null){
    String username=(String) session.getAttribute("username");
    return "登录用户:"+username;
    }
    return "登录用户为空";
    }

  • 第二种:使用注解的方式 (相较于其他方法,方法二更加的简洁)

    @RequestMapping("/getSession2")
      public String getSession2(@SessionAttribute String username){//默认是必传参数
          return "username"+username;
      }
    
  • 第三种:用servlet内置的HttpSession

    @RequestMapping("getSession3")
      public String getSession3(HttpSession session){//等价于HttpSession session=request.getSession(false);
          String username=(String)session.getAttribute("username");
          return "登录用户:"+username;
    

刚开始session是空的,cookie和session是有关联的,他们之间的桥梁是sessionId。我们现在来存储session,由于session是服务器端的,是无法通过浏览器进行构造,所以我们接下来进行构造session , 等发出了setSession的时候,请求中就会set-cookie(设置cookie),以sessionId来设置,后期获取到session,就是根据cookie中的sessionId来获取的到session对象,进而获取到用户信息。
我们设置session的时候,session创建了一个cookie,它们之间的桥梁是sessionId

等到获取session的时候,请求中就获取到了jsessionId.对应的用户信息。


发出请求,我们学习到了很多的注解,我们也会带上servlet原生封装的代码进行编写,两者编程方式做出了比较,用注解大大简化了代码,并不会像servlet一样。

复制代码
//解决问题
//400错误:客户端错误
//500错误:服务器错误(后端错误日志)
//2xx:成功
//3xx:重定向


//@RequestMapping设置路径
//@RequestParam设置可不传参数
//@RequestBody将json语言转成对象形式发出请求
//@PathVariable获取url中的参数(里面可以重命名)
//@RequestPart上传文件
//@CookieValue获取cookie(前端控制台中application中插入cookie)
//@SessionAttribute获取session,默认是必传参数,我们需要给required=false即可。
//@RequestHeader获取报头 里面的参数“需要获取的报头信息”

获得掌声,是我前进的动力。

相关推荐
Theodore_10228 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
LIT-涛1 天前
JavaEE初学07
数据库·oracle·java-ee
&梧桐树夏1 天前
JavaEE 线程安全
java-ee·多线程
界面开发小八哥1 天前
「Java EE开发指南」如何使用Visual JSF编辑器设计JSP?(一)
java·ide·java-ee·编辑器·myeclipse
先睡1 天前
javaEE
java·java-ee
冷心笑看丽美人1 天前
Spring 框架七大模块(Java EE 学习笔记03)
学习·spring·架构·java-ee
郑祎亦1 天前
JavaWeb开发:HTML 页面与接口对接
前端·后端·java-ee·html
Theodore_10222 天前
7 设计模式原则之合成复用原则
java·开发语言·jvm·设计模式·java-ee·合成复用原则
customer082 天前
【开源免费】基于SpringBoot+Vue.JS网上订餐系统(JAVA毕业设计)
java·jvm·vue.js·spring boot·spring cloud·java-ee·开源
Theodore_10222 天前
6 设计模式原则之单一职责原则
java·算法·设计模式·面试·java-ee·javaee·单一职责原则