0
点赞
收藏
分享

微信扫一扫

在Linux中部署ELK架构

90哦吼 2023-07-13 阅读 71

前言🍭

前篇我们讲了Spring日志,知道了日志的作用,日志怎么用以及通过lombok去进行更简单的日志输出,然后我们就基本讲完了Spring 相关知识,现在进入SpringMVC的学习。

一、什么是SpringMVC🍭

官方对于 Spring MVC 的描述是这样的:

Spring Web MVC :: Spring Framework

从上述官方定义的描述我们可以提取两个关键信息:

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

然而要真正的理解什么是 Spring MVC?我们首先要搞清楚什么是 MVC?

1、什么是MVC?🍉

MVC 是 Model View Controller 的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分

  • Model(模型)是应用程序中用于处理应⽤程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
  • View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
  • Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据, 控制用户输入,并向模型发送数据。

2、MVC 和 Spring MVC 的关系🍉

Spring MVC是基于MVC模式的Java Web开发框架,是Spring框架的一部分。Spring MVC提供了一种结构良好的开发模式,使得开发人员能够更好地组织和管理代码。它使用了MVC的概念,将应用程序的逻辑分离为模型、视图和控制器,并提供了一些额外的功能,如请求处理、表单验证、数据绑定等。是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架,当⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项目就可以感知到用户的请求。

因此,可以说Spring MVC是基于MVC模式的一种实现方式,它将MVC的概念应用于Web开发,并提供了一些与Web开发相关的功能和特性。

二、为什么要学 Spring MVC?🍭

现在绝大部分的 Java 项目都是基于 Spring(或 Spring Boot)的,而 Spring 的核心就是 Spring MVC。也就是说 Spring MVC 是 Spring 框架的核心模块,而 Spring Boot 是 Spring 的脚手架,因此 我们可以推断出,现在市⾯上绝⼤部分的 Java 项目约等于 Spring MVC 项⽬,这是我们要学 Spring MVC 的原因。

SpringMVC的优点:🍓

1. 轻量级:Spring MVC是一个轻量级的框架,它只提供了基本的Web开发功能,没有过多的冗余功能,使得应用程序的开发和部署更加高效。

2. 灵活性:Spring MVC采用了基于注解的配置方式,使得开发者可以更灵活地定义控制器、请求映射和视图解析等,极大地简化了开发过程。

3. 松耦合:Spring MVC采用了MVC设计模式,将应用程序的不同层次分离开来,使得各个模块之间的耦合度降低,提高了代码的可维护性和可测试性。

4. 可扩展性:Spring MVC提供了丰富的扩展点和插件机制,开发者可以根据自己的需求进行扩展和定制,满足各种复杂的业务需求。

5. 高度集成:Spring MVC与Spring框架紧密集成,可以很容易地与其他Spring组件(如Spring Boot、Spring Security等)进行集成,提供了更完整的解决方案。

6. 强大的视图解析能力:Spring MVC提供了多种视图解析器,支持多种视图技术(如JSP、Thymeleaf、Freemarker等),使得开发者可以根据自己的喜好选择合适的视图技术。

7. 易于测试:Spring MVC采用了面向接口的编程方式,使得控制器和服务层的代码可以很容易地进行单元测试,提高了代码的质量和稳定性。

在创建 Spring Boot 项⽬时,我们勾选的 Spring Web 框架其实就是 Spring MVC 框架,如下图所 示:

简单来说,咱们之所以要学习 Spring MVC 是因为它是⼀切项目的基础,我们以后创建的所有 Spring、Spring Boot 项目基本都是基于 Spring MVC 的。

三、怎么学 Spring MVC?🍭

学习 Spring MVC 我们只需要掌握以下 3 个功能:

  1. 连接的功能:将用户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调用到我们的 Spring 程序。
  2. 获取参数的功能:用户访问的时候会带⼀些参数,在程序中要想办法获取到参数。
  3. 输出数据的功能:执行了业务逻辑之后,要把程序执行的结果返回给用户。

对于 Spring MVC 来说,掌握了以上 3 个功能就相当于掌握了 Spring MVC。

1、Spring MVC 创建和连接🍉

Spring MVC 项目创建和 Spring Boot 创建项目相同(Spring MVC 使用 Spring Boot 的方式创建), 在创建的时候选择 Spring Web 就相当于创建了 Spring MVC 的项目。 在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射,也就是浏览器连接程序的作用。 

Ⅰ、创建SpringMVC项目🍓

  1. 使用Maven方式传统的创建SpringMVC(不过这已经是过时的方法)。
  2. 使用Spring Boot添加Spring Web模块(Spring MVC)。

创建步骤:

 创建之后,初始化完成:

接下来,创建⼀个 TextController 类,实现⽤户到 Spring 程序的互联互通,具体实现代码如下:  

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面
@RequestMapping("/text")//路由注册
public class TextController {
    
    @RequestMapping("/hi")//路由注册
    public String sayHi(){
        return "Hi,Spring MVC";
    }
}

 运行起来:

也可以使用@RestController代替@Controller+@ResponseBody

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
@RequestMapping("/text")//路由注册
public class TextController {

    @RequestMapping("/hi")//路由注册
    public String sayHi(){
        return "Hi,Spring MVC";
    }
}

Ⅱ、@RequestMapping 注解介绍🍓

@RequestMapping 是 Spring Web 应用程序中最常被用到的注解之⼀,它是用来注册接口的路由映射的。

@RequestMapping 即可修饰类,也可以修饰方法,当修饰类和方法时,访问的地址是类 + 方法。

@RequestMapping 也可以直接修饰方法,代码实现如下:

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
/*@RequestMapping("/text")//路由注册*/
public class TextController {

    @RequestMapping("/hi")//路由注册
    public String sayHi(){
        return "Hi,Spring MVC";
    }
}

 代码运行:

 Ⅲ、@RequestMapping 是 post 还是 get 请求?🍓

我们先在浏览器看一下这是post请求还是get请求?

 可以看到这是get请求。

下面使用 PostMan 测试⼀下,默认情况下使用注解 @RequestMapping 是否可以接收 GET 或 POST 请求?

我们测试之后发现在现在版本的@RequestMapping 既支持GET方式的请求有支持PSOT方式的请求。

GET: 

 POST

GET方法和POST方法有什么区别🍒

下面这篇文章讲解的十分详细了:

面试突击71:GET 和 POST 有什么区别? - 掘金 (juejin.cn)

指定 GET/POST 方法类型🍒

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
/*@RequestMapping("/text")//路由注册*/
public class TextController {

    @RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册
    public String sayHi(){
        return "Hi,Spring MVC";
    }
}

我们打开浏览器发现报错了,难道代码有问题?我们使用Postman看看 

 GET:

使用GET请求仍然报405,使用POST请求试试,发现可以访问:

这是因为我们设置了方法为POST,即只能使用POST请求去访问。我们的浏览器之前已经看了。它是GET请求。

Ⅳ、@GetMapping 和 PostMapping🍓

get 请求的 3 种写法:🍒

// 写法1
@RequestMapping("/hi")
// 写法2
@RequestMapping(value = "/hi",method = RequestMethod.GET)
// 写法3
@GetMapping("/hi")

 post 请求的 2 种写法:🍒

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

2、获取参数🍉

Ⅰ、传递单个/多个参数🍓

在 Spring MVC 中可以直接用方法中的参数来实现传参,比如以下代码:

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
/*@RequestMapping("/text")//路由注册*/
public class TextController {

    /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
    /*@PostMapping("/hi")*/
    @GetMapping("/hi")
    public String sayHi(String name){
        return "Hi"+name;
    }
}

不加参数,直接输出null 

添加name参数,输出:Hi 张三

 浏览器也是一样:

如果我们参数名错误(不同)则传递不成功:

如果我们传递了多个参数,其中有所需要的(参数名字相同),那它会自动匹配: 

Ⅱ、传递对象🍓

当参数个数过多时,可以进行传递对象,将参数封装成一个类。

Person对象

package com.example.mvcdemo.controller;

import lombok.Data;
@Data
public class Person {
    private int id;
    private String name;
    private String password;
}

TextController

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
/*@RequestMapping("/text")//路由注册*/
public class TextController {

    /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
    /*@PostMapping("/hi")*/
    @GetMapping("/hi1")
    public String sayHi1(Person p){
        return "Hi "+p.getId()+" "+p.getName()+" "+p.getPassword();
    }
}

 运行代码+传递参数:

注意事项🍒

package com.example.mvcdemo.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/*@Controller//让框架启动的时候加载当前类(只有加载的类,别人才能使用[访问])
@ResponseBody//告诉程序我返回的是一个数据而非页面*/
@RestController//@Controller+@ResponseBody
/*@RequestMapping("/text")//路由注册*/
public class TextController {

    /*@RequestMapping(value = "/hi",method= RequestMethod.POST)//路由注册*/
    /*@PostMapping("/hi")*/
    @GetMapping("/num")
    public String sayHi2(int num){
        return "num="+num;
    }
}

我们先正常传递参数:

但是如果我们忘记传递或是没有传递(前后端工作人员沟通不及时时),则会报错,而且这是非常严重的。

这个时候就很莫名其妙,也找不到错误。

如果我们将int换成它的包装类时:

正常传递参数可以正常显示:

 没有传递参数时它则会显示null,这就会很明显发现错误的来源。

Ⅲ、后端参数重命名(后端参数映射)🍓

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,比如前端传递了⼀个 time 给后端,而后端又是用 createtime 字段来接收的,这样就会出现参数接收不到的情况,如果出现 这种情况,我们就可以使用 @RequestParam 来重命名前后端的参数值。

具体示例如下,后端实现代码:

@RequestMapping("/m4")
public Object method_4(@RequestParam("time") String createtime) {
        System.out.println("时间:" + createtime);
        return "Hi "+createtime;
    }

代码运行: 

 这就说明参数的重命名生效了。

 还有需要注意的是使用了@RequestParam(),则这个参数是必须要传递的,我们可以看@RequestParam()源码:

没有传递参数时:

@RequestMapping("/m4")
public Object method_4(@RequestParam(value = "time", required = false) String createtime) {
        System.out.println("时间:" + createtime);
        return "Hi "+createtime;
    }+ createtime);

Ⅳ、@RequestBody 接收JSON对象🍓

我们先来试试看接受对象的是否可以接收JSON对象:

@GetMapping("/hi1")
    public String sayHi1(@RequestBody Person p){
        return p.toString();
    }

使用Postman 传递JSON对象

传递的是 0 null null ,就发现传递不了。那我们传递JSON对象时应该任何传递?

使用@RequestBody 注解。

    @PostMapping("/hi1")
    public String sayHi1(@RequestBody Person p){
        return "Hi "+p.getId()+" "+p.getName()+" "+p.getPassword();
    }

不过当@RequestBody传递JSON格式对象时需要配合PostMapping一起使用,因为@RequestBody传递JSON格式对象时是Post类型传参。

Postman:

Ⅴ、获取URL中参数@PathVariable🍓

后端实现代码:

@PostMapping("/m6/{name}/{password}")
    public Object method_6(@PathVariable String name, @PathVariable String password) {
        return "name:" + name+" password:" + password;
    }

Ⅵ、上传文件@RequestPart🍓

@RequestMapping("/m9")
    public String upFile(@RequestPart("myfile") MultipartFile file) throws IOException {
        // ⽂件保存地址
        String filePath = "C:\\Users\\lin\\Pictures\\JiangHai\\11.png";
        // 保存⽂件
        file.transferTo(new File(filePath));
        return filePath + " 上传成功.";
    }

 文件夹什么都没有:

使用Postman进行上传文件:

随便选择一张图片(文件名为myFile)

上传成功:

 我们也可以打开这张图片

但是我们发现我们把路径定死了,这在实际开发中是不可能的,那我们现在来写一个最终版的文件上传:

@RequestMapping("/upfile")
    public String myUpFile(@RequestPart("myupfile") MultipartFile file) throws IOException {
        //根目录
        String path ="C:\\Users\\lin\\Pictures\\JiangHai\\";
        //根目录+唯一文件名(进行随机取名)
        path+=UUID.randomUUID().toString();
        //根目录+唯一文件名+文件的后缀 ex: aaa.aaa.png
        path+=file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
            file.transferTo(new File(path));
            return path + " 上传成功";
    }

再随便上传一张图片 

我们也可以上传一个.txt文件:

上传成功: 

 注意:字段myfile允许的最大大小为1048576字节(即上传的文件是有大小限制的)

Ⅶ、获取Cookie/Session/header🍓

获取 Request 和 Response 对象 🍒

//Spring MVC(Spring Web) 内置了HttpServletRequest 和 HttpServletResponse
    @RequestMapping("/getparam")
    public String param10(HttpServletRequest request) {
        return request.getParameter("name");
    }

通过获取Request对象获取参数: 

 获取Cookie🍒

@RequestMapping("/getck")
    public String getCookie( HttpServletRequest request) {
        // 获取所有 cookie 信息
        Cookie[] cookies = request.getCookies();
        for(Cookie item:cookies){
            log.error(item.getName()+" "+item.getValue());
            //log的使用需要添加@Slf4j注解
        }
        return "get cookie!";
    }

打开浏览器开发人员工具(F12) ,手动添加结果Cookie:

 浏览器访问 localhost:8080/getck

控制台就会将我们的Cookie打印出来: 

@RequestMapping("/getck2")
    public String getCookie2(@CookieValue("zhangsan") String val) {
        return "Cookie Value: "+val;
    }

 为什么浏览器会去实现这个机制呢?

 简洁获取 Header—@RequestHeader🍒

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

浏览器:

Session 存储和获取🍒

Session 存储和 Servlet 类似,是使⽤ HttpServletRequest 中获取的,如下代码所示

@RequestMapping("/setsess")
    public String setsess(HttpServletRequest request) {
        // 获取 HttpSession 对象,参数设置为 true 表示如果没有 session 对象就创建⼀个session
        HttpSession session = request.getSession(true);
        if(session!=null){
            session.setAttribute("username","username");
        }
        return "session 存储成功";
    }

 读Session①

//读Session1
    @RequestMapping("/getsess")
    public String sess(HttpServletRequest request) {
        // 如果 session 不存在,不会⾃动创建
        HttpSession session = request.getSession(false);
        String username = "暂⽆";
        if(session!=null && session.getAttribute("username")!=null){
            username = (String) session.getAttribute("username");
            return (String)session.getAttribute("username");
        }
        return "暂无Session信息!";
    }

 读Session②(更简洁的方式

//读Session2
    @RequestMapping("/getsess2")
    public String sess2(@SessionAttribute(value = "username",required = false)
                        String username) {
        return "username:"+username;
    }

3、返回数据🍉

Ⅰ、返回静态页面🍓

创建前端页面 hello.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>hello,spring mvc</title>
    <script src="index.js"></script>
</head>
<body>
<h1>Hello,Spring MVC.</h1>
</body>
</html>

创建控制器 RespController

package com.example.mvcdemo.controller;


import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/resp")
public class RespController {
    @RequestMapping("/hi")
    public String sayHi(String name){
        return "/hello.html";
    }
}

Ⅱ、返回text/html🍓

Ⅲ、返回 JSON 对象🍓

@ResponseBody
    @RequestMapping("/m8")
    public HashMap<String, String> method_8() {
        HashMap<String, String> map = new HashMap<>();
        map.put("Java", "Java Value");
        map.put("MySQL", "MySQL Value");
        map.put("Redis", "Redis Value");
        return map;
    }

Ⅳ、请求转发或请求重定向🍓

forward VS redirect

return 不但可以返回⼀个视图,还可以实现跳转,跳转的方式有两种:

  • forward :请求转发;
  • redirect:请求重定向。

请求转发和重定向的使用对比:

// 请求重定向
@RequestMapping("/hello")
public String hello(){
     return "redirect:/hello.html";
}
// 请求转发
@RequestMapping("/hello2")
public String hello2(){
     return "forward:/hello.html";
}

forward 和 redirect 具体区别如下:

  1. 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
  2. 请求重定向地址发⽣变化,请求转发地址不发⽣变化。
  3. 请求重定向与直接访问新地址效果⼀直,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。

请求转发如果资源和转发的页面不在⼀个目录下,会导致外部资源不可访问 。

四、送书活动🍭

Spring Cloud Alibaba核心技术与实战案例

本书特色:

不留遗漏:全面覆盖Dubbo核心知识点

直击要害:实战化案例精准定位技术细节

学以致用:精要式演示确保开发、学习不脱节

潜移默化:研磨式知识讲解渗透技术要点

提升效率:垂直式技术精讲不饶弯路

循序提升:渐进式知识点编排确保连贯

配套资源:赠送全书案例源文件助力学习

作者简介

高洪岩,某世界500强公司项目经理,有10年Java开发和项目管理经验,精通Java语言,擅长Java EE、分布式、微服务、高性能服务器架构、

智能报表、多线程和高并发相关的技术内容,理论与实践经验颇丰,也积极参与开源项目的开发与设计,涉及Dubbo、Jedis、Pulsar、ZooKeeper等主流开源项目。

著有《Java多线程编程核心技术》《Java并发编程:核心方法与框架》《NIO与Socket编程技术指南》《Java EE核心框架实战(第2版)》《Java Web实操》《虚拟化高性能NoSQL存储案例精粹:Redis+Docker》等多本图书。

京东链接:https://item.jd.com/14010448.html

举报

相关推荐

0 条评论