• Spring MVC 的使用


    目录

    1. 什么是Spring MVC

    1.1 MVC 定义

    1.2 MVC 和 Spring MVC 的关系

    2. Spring MVC 需要掌握的功能

    2.1 Spring MVC 创建和连接

     2.1.1 @RequestMapping 注解

     2.1.2 @GetMapping 和 @PostMapping

    ​编辑2.2 获取参数

    2.2.1 传递单个参数

    2.2.2 获取多个参数

     2.2.3 传递对象

    2.2.4 后端参数重命名@RequestParam(后端参数映射)

    2.2.5 @RequestParam注意事项 

    2.2.6 @RequestBody 接收JSON对象

    2.2.7 获取URL中的参数@PathVariable 

     2.2.8 上传文件@RequestPart

    2.2.9 获取Cookie 

     2.2.10 Session存储和获取

     2.3 返回数据

    2.3.1 返回静态页面 (不加@ResponseBody 注解)

    2.3.2 返回非静态@ResponseBody

    2.3.3 实现登录功能

    2.3.4 请求转发或请求重定向

     2.3.5 forward 和 redirect 的具体区别


    1. 什么是Spring MVC

    1)Spring MVC 是⼀个 Web 框架。
    2)S pring MVC 是基于 Servlet API 构建的

    1.1 MVC 定义

     MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分

    为模型、视图和控制器三个基本部分。

     1)Model (模型)是应用程序中用于处理应用程序数据逻辑的部分通常模型对象负责在数据库中           存取数据。

    2)View(视图)是应⽤程序中处理数据显示的部分。通常视图是依据模型数据创建的。

    3)Controller(控制器)是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据,

           控制⽤户输⼊,并向模型发送数据。

    1.2 MVC 和 Spring MVC 的关系

    MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。
    总结来说,Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。既然是 Web 框架,那么当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项⽬就可以感知到⽤户的请求。
    Spring MVC 是因为它是⼀切项⽬的基础,我们以后创建的所有 Spring、Spring Boot 项⽬基本都是基于 Spring MVC 的。

    2. Spring MVC 需要掌握的功能

    1.连接功能:实现用户和程序的映射(在浏览器输入 URL 地址之后,能够在程序中匹配到相应的方法)。

    2.获取参数的功能:服务器要得到用户的请求参数。

    3. 输出数据功能:服务器端将结果返回给用户(前端)。

    2.1 Spring MVC 创建和连接

    Spring MVC 项⽬创建和 Spring Boot 创建项⽬相同,勾选上 Spring Web 模块即可 。然后在启动类DemoApplication 同级目录下创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:
    1. @Controller //让spring启动时,加载
    2. @ResponseBody //返回一个非静态页面的数据,text/HTML等。不加的话会返回默认静态页面
    3. @RequestMapping("/user") //路由
    4. public class UserController {
    5. @RequestMapping("/say") //路由
    6. public String say() {
    7. return "hello springmvc";
    8. }
    9. }

    连接成功并获取

     2.1.1 @RequestMapping 注解

    @RequestMapping 是 Spring Web 应⽤程序中最常被⽤到的注解之⼀,它是⽤来注册接⼝的路
    由映射的。
    路由映射:所谓的路由映射指的是,当⽤户访问⼀个 url 时,将⽤户的请求对应到程序中某个类的某个⽅法的过程就叫路由映射

    @RequestMapping 基础使用: 

    即可修饰类,也可以修饰⽅法
    即支持GET 请求,也指出POST 请求,但默认情况下是GET 请求

     我们可以显示的指定 @RequestMapping 来接收 POST 的情况,如下所示

    1. @RequestMapping(method = RequestMethod.POST,value = "say2")
    2. public String say2() {
    3. return "hello,hello";
    4. }

     通过 postman 来验证

    post请求

     get请求

     从上面可以指定,当通过 meth 指定请求方式之后,是不能用另一种方式来访问的

     2.1.2 @GetMapping 和 @PostMapping

    1)get请求,有三种写法

    1. // 写法1
    2. @RequestMapping("/index")
    3. // 写法2
    4. @RequestMapping(method = RequestMethod.GET,value = "/index",)
    5. // 写法3
    6. @GetMapping("/index")

    @GetMapping  

    1. @GetMapping("/get")
    2. public String say3() {
    3. return "getMapping";
    4. }

    在使用get请求时

     在使用post请求时

    2)post请求,两种写法

    1. // 写法1
    2. @RequestMapping(method = RequestMethod.POST,value = "/index")
    3. // 写法2
    4. @PostMapping("/index")

    @PostMapping

    1. @PostMapping
    2. public String say4() {
    3. return "postMapping";
    4. }

    get请求

    2.2 获取参数

    2.2.1 传递单个参数

    1)在 Spring MVC 中可以直接⽤⽅法中的参数来实现传参
    直接在容器类中写入下面代码
    1. @RequestMapping("/method")
    2. public Object method(String name) {
    3. System.out.println("name: " + name);
    4. return "name: " + name;
    5. }

    获取结果

    2)创建一个对象类

    1. @Data
    2. public class UserInfo {
    3. private int id;
    4. private String username;
    5. private String password;
    6. private int age;
    7. }

    在容器类 UserController 中获取 

    1. @RequestMapping("/getuserbyid")
    2. public UserInfo getUserById(Integer id) {
    3. UserInfo userInfo = new UserInfo();
    4. userInfo.setId(id);
    5. userInfo.setUsername("黄小小");
    6. userInfo.setAge(18);
    7. return userInfo;
    8. }

    访问时,要将 id 传参进去 

    2.2.2 获取多个参数

    1. //获取多个参数
    2. @RequestMapping("/login")
    3. public String login(String username, String password) {
    4. return "用户名: " + username + " | 密码: " + password;
    5. }

     2.2.3 传递对象

    直接将对象的类名传入即可

    1. //获取对象
    2. @RequestMapping("/reg")
    3. public String reg(UserInfo userInfo) {
    4. return "用户信息: " + userInfo;
    5. }

    2.2.4 后端参数重命名@RequestParam(后端参数映射)

     某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,比如前端传递一个 name 给后端,但是后端使用的是 username 来接收,这样就出现参数不统一,而接收不到,修改起来又麻烦。

    这时就需要使用 @RequestParam 来重命名前后端的参数值。(此方法支持在参数里,对象里不行)

    例如:

    1. @RequestMapping("/login")
    2. public String login(String username, String password) {
    3. return "用户名: " + username + " | 密码: " + password;
    4. }

    后端使用 username来接收,但是前端使用name来进行 获取,这样是获取不到的,如下

     使用 @RequestParam 来重命名前后端的参数值

    1. @RequestMapping("/login")
    2. public String login(@RequestParam("name") String username, String password) {
    3. return "用户名: " + username + " | 密码: " + password;
    4. }

    访问情况 ,可以访问 

    2.2.5 @RequestParam注意事项 

    如果在参数中添加 @RequestParam 注解,那么前端一定要传递此参数,否则会报错

    想要解决此问题,可以给@RequestParam里面添加 required = false

    例:

    1. @RequestMapping("/login2")
    2. public String login2(@RequestParam("name") String username, String password) {
    3. return "用户名: " + username + " | 密码: " + password;
    4. }

     添加 required = false 之后

    1. @RequestMapping("/login2")
    2. public String login2(@RequestParam(value = "name",required = false) String username, String password) {
    3. return "用户名: " + username + " | 密码: " + password;
    4. }

    2.2.6 @RequestBody 接收JSON对象

     后端代码:

    1. //获取对象,json 格式
    2. @RequestMapping("/regjson")
    3. public String regJson(@RequestBody UserInfo userInfo) {
    4. return "用户信息: " + userInfo;
    5. }

     通过postman 来模拟后端接收

     fiddler 抓包

    2.2.7 获取URL中的参数@PathVariable 

    1. @PostMapping("/info/{name}/{password}")
    2. public String getInfo(@PathVariable String name,@PathVariable String password) {
    3. return "name: " + name + " | password: " + password;
    4. }

     2.2.8 上传文件@RequestPart

    1. @RequestMapping("/upimg")
    2. public boolean unImg(Integer id, @RequestPart("img")MultipartFile file) {
    3. boolean flg = false;
    4. //保存图片到本地目录
    5. try {
    6. file.transferTo (new File("D:/Img/img.jpg"));
    7. flg = true;
    8. } catch (IOException e) {
    9. log.error("上传图片失败: " + e.getMessage());
    10. }
    11. return flg;
    12. }

     

     上面的上传代码有缺陷,就是再重新上传的话,会覆盖原来的文件,需要改进,如下

    1. @RequestMapping("/upimg")
    2. public boolean upImg(Integer id, @RequestPart("img")MultipartFile file) {
    3. boolean flg = false;
    4. //1.保存图片到本地目录 imgPath
    5. //2.图片名称(图片名不能重复)
    6. //3.获取原上传图片的格式
    7. String fileName = file.getOriginalFilename();//文件原名
    8. fileName = fileName.substring(fileName.lastIndexOf(".")); //得到文件后缀名
    9. fileName = UUID.randomUUID().toString() + fileName; //随机生成文件名 + 后缀名
    10. try {
    11. file.transferTo (new File( imgPath + fileName));
    12. flg = true;
    13. } catch (IOException e) {
    14. log.error("上传图片失败: " + e.getMessage());
    15. }
    16. return flg ;
    17. }

    可以上传多个,并且不会覆盖之前上传的,名字也是随机的 

    2.2.9 获取Cookie 

    1)获取Request 对象

    1. @RequestMapping("/cookie")
    2. public String getCookie(HttpServletResponse response,HttpServletRequest request) {
    3. // 得到全部的 Cookie
    4. String name = request.getParameter("name: ");
    5. Cookie[] cookies = request.getCookies();
    6. return name + "hello";
    7. }
    简洁的获取 Cookie—@CookieValue
    1. @RequestMapping("/cookie2")
    2. public String getCookie2(@CookieValue("fly") String cookie) {
    3. return "Cookie Value: " + cookie;
    4. }

    fly 的value 就是 666

    2)获取请求头 Header—@RequestHeader

    1. @RequestMapping("/getua2")
    2. public String getHead2(@RequestHeader("User-Agent") String userAgent) {
    3. return "header:" + userAgent;
    4. }

     2.2.10 Session存储和获取

    1)Session 存储和 Servlet 类似,是使⽤ HttpServletRequest 中获取的,如下代码所示:
    1. @RequestMapping("/setsession")
    2. public boolean setSession(HttpServletRequest request) {
    3. boolean result = false;
    4. //1.得到HttpSession
    5. HttpSession session = request.getSession(true);
    6. //2.使用setAtt 设置值
    7. session.setAttribute("userinfo","userinfo");
    8. result = true;
    9. return result;
    10. }

    存储成功之后,会有一个默认的JSESSIONID 返回后端

     

     2)Session 获取

    1. @RequestMapping("/getsession")
    2. public String getSession(HttpServletRequest request) {
    3. String result = null;
    4. //1.得到 HttpSession 对象
    5. HttpSession session = request.getSession(false); //false=如果右会话,就会使用会话,如果没有,那么不会新创建会话
    6. //2.getAtt 得到Session 信息
    7. if (session != null && session.getAttribute("userinfo") != null) {
    8. result = (String) session.getAttribute("userinfo");
    9. }
    10. return result;
    11. }

    要想获取 session 就先要执行上面的存储,才能获取

    如果一开始就想获取的话,是不可以的 

    简便的 Session 获取

    1. //简便获取sessio
    2. @RequestMapping("/getsession2")
    3. public String getSession2(@SessionAttribute(value = "userinfo",
    4. required = false) String userinfo) {
    5. return "会话: " + userinfo;
    6. }

     2.3 返回数据

    默认请求下⽆论是 Spring MVC 或者是 Spring Boot 返回的是视图 (xxx.html),⽽现在都是前后端分离的,后端只需要返给给前端数据即可,这个时候我们就需要使⽤ @ResponseBody 注解。
    组合注解 @RestController = @Controller + @ResponseBody ,返回非静态页面

    2.3.1 返回静态页面 (不加@ResponseBody 注解)

    前端页面

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <h1 style="color:red">hello.htmlh1>
    9. body>
    10. html>
    创建控制器 TestController:
    1. @Controller
    2. public class TestController {
    3. @RequestMapping("/say")
    4. public String say() {
    5. return "hello.html";
    6. }
    7. }

    2.3.2 返回非静态@ResponseBody

    实现计算器功能。

    前端

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>计算器title>
    6. head>
    7. <body>
    8. <form action="/calc">
    9. <h1>计算器h1>
    10. 数字1:<input name="num1" type="text"><br>
    11. 数字2:<input name="num2" type="text"><br>
    12. <input type="submit" value=" 点击相加 ">
    13. form>
    14. body>
    15. html>
    后端
    1. @Controller
    2. @ResponseBody
    3. public class CalcController {
    4. @RequestMapping("/calc")
    5. public String calc(Integer num1, Integer num2) {
    6. if (num1 == null || num2 == null) return "

      参数错误

      返回"
      ;
    7. return "

      结果: " + (num1 + num2) + "

      返回"
      ;
    8. }
    9. }

    2.3.3 实现登录功能

    前端使用 Ajax,后端使用JSON给前端

    1. @RequestMapping("/login3")
    2. public HashMap login2(@RequestBody UserInfo userInfo) {
    3. HashMap result = new HashMap();
    4. int state = 200;
    5. int data = -1;//等于 1,登录成功,否则登录失败
    6. String msg = "未知错误";
    7. if (StringUtils.hasLength(userInfo.getUsername()) && StringUtils.hasLength(userInfo.getPassword())) {
    8. if (userInfo.getUsername().equals("fly") && userInfo.getPassword().equals("123")) {
    9. data = 1;
    10. msg = "";
    11. } else {
    12. msg = "用户名或密码错误";
    13. }
    14. } else {
    15. msg = "非法参数";
    16. }
    17. result.put("state",state);
    18. result.put("data",data);
    19. result.put("msg",msg);
    20. return result;
    21. }

    前端

    1. <head>
    2. <meta charset="UTF-8">
    3. <script src="js/jquery-1.9.1.min.js">script>
    4. <title>登录title>
    5. head>
    6. <body>
    7. <div style="text-align: center;">
    8. <h1>登录h1>
    9. 用户:<input id="username">
    10. <br>
    11. 密码:<input id="password" type="password">
    12. <br>
    13. <input type="button" value="提交" onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
    14. div>
    15. body>
    16. <script>
    17. // ajax 提交
    18. function mysub(){
    19. // 1.判空
    20. var username = jQuery("#username");
    21. var password = jQuery("#password");
    22. if(jQuery.trim(username.val())==""){
    23. alert("请先输入用户名!");
    24. username.focus(); // 光标重制到此元素
    25. return;
    26. }
    27. if(jQuery.trim(password.val())==""){
    28. alert("请先输入密码!");
    29. password.focus(); // 光标重制到此元素
    30. return;
    31. }
    32. jQuery.ajax({
    33. url:"/user/login3",
    34. type:"POST",
    35. contentType:"application/json",
    36. data:JSON.stringify({"username":username.val(),
    37. "password":password.val()}),
    38. success:function(result){
    39. alert(JSON.stringify(result));
    40. }
    41. });
    42. }
    43. script>

    登录效果:

     

    2.3.4 请求转发或请求重定向

    1)请求转发(forward)实现方式 1

    服务器帮用户实现

    1. @RequestMapping("/for")
    2. public String myForward() {
    3. return "forward:/hello.html";
    4. }

    1)请求转发(forward)实现方式 2

    1. @RequestMapping("/for2")
    2. public void myForward2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    3. request.getRequestDispatcher("/hello.html").forward(request,response);
    4. }

     3)请求重定向(redirect) 方式1

    1. @RequestMapping("/rd")
    2. public String myRedirect() {
    3. return "redirect:/hello.html";
    4. }

    重定向的请求发生在客户端(浏览器),服务器端不会提出用户进行请求操作

    抓包结果

      4)请求重定向(redirect) 方式2

    1. @RequestMapping("/rd2")
    2. public void myRedirect2(HttpServletResponse response) throws IOException {
    3. response.sendRedirect("/hello.html");
    4. }

    抓包结果

     2.3.5 forward 和 redirect 的具体区别

    1)定义不同

    2)跳转方不同

    3)数据共享不同

    4)最终 URL 地址不同

    5)代码实现不同

  • 相关阅读:
    【Pytorch with fastai】第 15 章 :深入探讨应用程序架构
    全新锂电池充电板,让充电更加安全
    ​CUDA学习笔记(三)CUDA简介
    【C语言】错题本(2)
    nginx学习笔记
    EclipseLink
    CMS指纹识别
    油/水溶性CdS-ZnS/InP-ZnS/ZnSe-ZnS/CdSe/ZnS量子点的应用
    ChatGLM-6B-Int4运行有误
    Linux 查看权限控制
  • 原文地址:https://blog.csdn.net/m0_60494863/article/details/125892795