• SpringMVC 程序开发


    ✏️作者:银河罐头
    📋系列专栏:JavaEE

    🌲“种一棵树最好的时间是十年前,其次是现在”

    什么是 Spring MVC

    SSM = Spring Boot + Spring Web(Spring MVC) + MyBatis

    Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称"Spring Web MVC"来自其源模块的名称(Spring-webmvc), 但它通常被称为"Spring MVC".

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

    MVC 定义

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

    image-20230524210331588

    怎么学 Spring MVC

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

    1.连接的功能:将⽤户(浏览器)和 Java 程序连接起来,也就是访问⼀个地址能够调⽤到我们的 Spring 程序

    2.获取参数的功能:⽤户访问的时候会带⼀些参数,在程序中要想办法获取到参数。

    3.输出数据的功能:执⾏了业务逻辑之后,要把程序执⾏的结果返回给⽤户。

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

    Spring MVC 创建和连接

    创建 Spring MVC 项目

    2018年之前,使用 maven 项目添加 Spring MVC 框架的方式来创建,太复杂。

    2018年之后 ,使用 Spring Boot 来创建 Spring MVC 项目。

    @RestController
    public class UserController {
    
        @RequestMapping("/say")//可以是 1 级路由,也可以是 n 级路由
        public String sayHi(){
            return "hi spring mvc";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    image-20230525093524841

    实现用户到 spring 程序的连接。

    @RequestMapping 注解介绍

    它支持 GET 请求

    image-20230525094012167

    那它是否支持 post 请求?

    postman 测试:

    image-20230525094308605

    得出结论:它也支持 POST 请求.

    image-20230525094720999

    GET, HEAD, POST,PUT, PATCH, DELETE, OPTIONS, TRACE 都支持。

    在浏览器地址栏输入地址,默认是 GET 请求。

    • 如果我想设置成只支持其中某一种请求类型,如何实现?
    @RestController
    public class UserController {
        @RequestMapping(value = "/sayhi",method = RequestMethod.POST)
        public String sayHi(){
            return "hi spring mvc";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    image-20230525095737251

    设置成只支持 POST 请求,再发 GET 请求就失败了。

    @PostMapping

    除了通过 @RequestMapping 来设置 POST,还可以通过@PostMapping 来设置。

    @PostMapping("/sayhello")
    public String sayHello(){
        return "hello spring mvc";
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525101343151

    小结:

    2种实现路由连接的方式 :@RequestMapping 和 @PostMapping

    @GetMapping("/hi")
    public String hi(){
        return "spring mvc hi";
    }
    
    • 1
    • 2
    • 3
    • 4

    获取参数

    获取单个参数

    @RequestMapping("/sayhi")
    public String sayHi(String name){
        return "hi " + name;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525104224079

    这里地址栏里 key 必须写"name", 才能成功拿到 value

    image-20230525104425955

    image-20230525104553806

    如果传了错误的 key 或者不传参数 ,结果就是String 的默认值 null

    @RequestMapping("/sayhi2")
    public String sayHi2(Integer id){
        return "hi " + id;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525104909702

    @RequestMapping("/sayhi3")
    public String sayHi3(int id){
        return "hi " + id;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525104950110

    参数传递不要使用基本数据类型(如 int)。

    @RequestMapping("/sayhi4")
    public String sayHi4(HttpServletRequest request, HttpServletResponse response){
        return "hi " + request.getParameter("name");
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525105923750

    @RequestMapping("/sayhi4")
    public String sayHi4(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.sendRedirect("https://www.sogou.com");
    }
    
    • 1
    • 2
    • 3
    • 4

    还可以实现重定向跳转页面。

    获取多个参数

    @RequestMapping("/sayhi")
    public String sayHi(String name, String password){
        return "name =  " + name + "  | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525120905027

    参数顺序不重要,保证 key 正确就行。

    传递对象

    @Data
    public class Userinfo {
        private int id;
        private String name;
        private String password;
        private int age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    //获取对象
    @RequestMapping("/reg")
    public Object reg(Userinfo userinfo){
        return userinfo;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20230525121910432

    @RequestMapping("/h1")
    public Object getH1(){
        return "

    我是 h1

    "
    ; }
    • 1
    • 2
    • 3
    • 4

    image-20230525122546245

    后端参数重命名

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

    @RequestMapping("/reg2")
    public Object reg(@RequestParam("username") String name, String password){
        return "name = " + name + "  | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230525123606776

    如果前端传的是 name, 会怎样?

    image-20230525124506164

    image-20230525124602939

    规定 前端必须传 “username”.

    @RequestMapping("/reg2")
    public Object reg(@RequestParam(value = "username",required = false) String name, 
                      String password){
        return "name = " + name + "  | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    required = false 设置之后

    image-20230525124843490

    前端:对象/JSON 对象字符串

    后端:对象/JSON 对象字符串

    @RequestBody 接收JSON对象

    用之前接收对象的方式,不能成功接收到 JSON 对象。

    @RequestMapping("/reg")
    public Object reg(Userinfo userinfo){
        System.out.println(userinfo);
        return userinfo;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    用 postman 发送一个 post 请求。

    image-20230526161624662

    用 @RequestBody 这个注解就可以成功接收到 JSON 对象了。

    @RequestMapping("/reg3")
    public Object reg3(@RequestBody Userinfo userinfo){
        return userinfo;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230526162053237

    获取URL中参数@PathVariable

    /user?uid=12345

    /user/12345 优点:搜索引擎抓取关键字权重更高,更简洁

    @RequestMapping("/reg4/{name}/{password}")
    public Object reg4(@PathVariable String name, @PathVariable String password){
        return "name = " + name + " | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230526173548560

    如果把路径里的 password 改成 pwd,会怎样?

    image-20230526173830789

    image-20230526173849026

    image-20230526173933382

    这个参数是必须的。所以会报错。

    @RequestMapping("/reg4/{name}/{pwd}")
    public Object reg4(@PathVariable String name, @PathVariable(required = false) String password){
        return "name = " + name + " | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230526174116844

    加 required = false 之后就不会报错,但是 还是得不到 password 的值。

    小结:

    @PathVariable: 基础 url 里面的参数(? 之前的参数)

    @RequestParam: url 参数部分的参数(? 之后的参数)

    @RequestMapping("/reg4/{name}/{pwd}")
    public Object reg4(@PathVariable String name, @PathVariable(required = false,name = "pwd") String password){
        return "name = " + name + " | password = " + password;
    }
    
    • 1
    • 2
    • 3
    • 4

    image-20230526175020377

    上传文件@RequestPart

    @RequestMapping("/myupload")
    public Object upload(@RequestPart("myimg")MultipartFile file){
        File saveFile = new File("D:\\Data\\myimg.png");
        try {
            file.transferTo(saveFile);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    用 postman 发送 post 请求:

    image-20230526185447372

    image-20230526185519850

    文件上传成功。

    默认要求上传单个文件大小不超过 1MB.

    Common Application Properties (spring.io)

    image-20230526191038458

    如果我要上传的文件很大怎么办?

    image-20230526192305252

    可以设置上传文件大小。

    有一个问题,后面上传的文件会把之前的文件覆盖。

    MySQL -> InnoDB(5.5) -> B+存储 -> 聚簇索引树

    叶子(数据页) 主键(如果有) + 数据

    • 如何保证每次上传的文件不会覆盖?也就是最终保存的是不同的文件名。

    UUID。

    image-20230526194438761

    //上传文件
    @RequestMapping("/myupload")
    public Object upload(@RequestPart("myimg")MultipartFile file){
        String fileName = UUID.randomUUID() + //文件名
                file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));//后缀名
        File saveFile = new File("D:\\Data\\" + fileName);
        try {
            file.transferTo(saveFile);
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    image-20230526195229489

    成功上传,没有覆盖原有的。

    获取Cookie/Session/header

    //获取 cookie
    @RequestMapping("/getCookie")
    public Object getCookie(@CookieValue(value = "java",required = false) String java){
        return "java = " + java;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20230526203510999

    我们可以手动构造一个 cookie。

    image-20230526203720519

    • 获取 Header
    //获取 header
    @RequestMapping("/header")
    public Object getHeader(@RequestHeader("user-agent") String userAgent){
        return "userAgent = " + userAgent;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20230526204630024

    • 获取 Session
    private static final String SESSION_KEY = "USERINFO_SESSION_KEY";
    //存储 session
    @RequestMapping("/setSession")
    public void setSession(HttpServletRequest request){
        HttpSession session = request.getSession();//没有就创建,默认是 true
        session.setAttribute(SESSION_KEY,"zhangsan");
    }
    //获取 session
    @RequestMapping("/session")
    public Object getSession(@SessionAttribute(SESSION_KEY) String name){
        return "session = " + name;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    image-20230526211355550

    返回数据

    1)返回静态页面

    @Controller
    @RequestMapping("/test")
    public class TestController {
    
        @RequestMapping("/getIndex")
        public Object getIndex(){
            return "index.html";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    image-20230526212609378

    image-20230526212624263

    确认 target 下有 index.html.

    那是什么原因?

    image-20230527152437083

    加了"/"之后就能访问成功了。

    image-20230527152527859

    加了"/“表示是 从根目录去找"index.html”, 不加"/"是在 test 目录下去找 "index.html"就找不到.

    image-20230527152858995

    image-20230527153309749

    2)请求转发或请求重定向

    1.请求转发

    //请求转发
    @RequestMapping("/forward")
    public String forward(){
        return "forward:/index.html";
        //return "/index.html"; 默认就是请求转发
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    image-20230527163136991

    2.请求重定向

    //请求重定向
    @RequestMapping("/redirect")
    public String redirect(){
        return "redirect:/index.html";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    image-20230527163210272

    @RequestMapping("/redirect2")
    public void redirect2(HttpServletResponse response) throws IOException {
        response.sendRedirect("https://www.baidu.com");
    }
    
    • 1
    • 2
    • 3
    • 4

    forward 和 redirect 具体区别如下:

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

    举例:

    请求转发:张三找李四借钱,李四自己也没钱,李四又去找王五借,最终张三只借了一次钱,剩下的事都是 李四干的。

    请求重定向:张三找李四借钱,李四自己也没钱,李四告诉张三说自己没钱让张三去找王五借钱。然后张三又去找王五借到了钱。

    请求转发和请求重定向有什么区别? | Javaᶜⁿ 面试突击 (javacn.site)

  • 相关阅读:
    高仿京东Android App,集成React-Native热更
    Java开发者的Golang进修指南:从0->1带你实现协程池
    网络安全(黑客)自学
    How to transition ION to DMA-BUF heaps
    Spring Cloud 部署时如何使用 Kubernetes 作为注册中心和配置中心
    后端接口性能优化分析-多线程优化
    MySQL的高阶语句
    Java项目实战记录:雷达数据插值
    Element UI之Cascader 级联选择器
    什么是半波整流器?半波整流器的使用方法
  • 原文地址:https://blog.csdn.net/qq_63983125/article/details/130903666