JavaEE【Spring】:SpringMVC 程序开发

一、概念

官方给出的定义:

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

总结:

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

1、MVC 定义

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

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

2、MVC 和 Spring MVC 的关系

MVC 是⼀种思想,⽽ Spring MVC 是对 MVC 思想的具体实现。

3、Spring MVC 和 Spring 的关系

绝⼤部分的 Java 项⽬都是基于 Spring(或 Spring Boot)的,⽽ Spring 的核⼼就是 Spring MVC。

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

二、Spring MVC 创建和连接

1、创建 Spring MVC 项目

Spring MVC 项目的创建其实我们之前已经学习过了,和 Spring Boot 项目创建是一模一样的:
在这里插入图片描述
在这里插入图片描述
接下来,创建⼀个 UserController 类,实现⽤户到 Spring 程序的互联互通,代码如下:

@Controller // 在 Spring 启动的时候,加载并注册
@ResponseBody // 当前类返回非静态页面
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    @RequestMapping("/hi") // 路由器规则注册
    public Object sayHi() {
    
    
        return "Hi,Spring MVC.";
    }

}

访问 http://localhost:8080/web/hi,运行结果为:
在这里插入图片描述

① 对比

  • @Controller:在 Spring 启动的时候,加载并注册,这个注解也是必须的,否则访问不到 Bean 对象。
  • @ResponseBody:当前类返回非静态页面,这个注解一般情况下是必须的,但如果返回静态页面,也可以不加这个注解。
@Controller // 在 Spring 启动的时候,加载并注册
public class WebController {
    
    

    @RequestMapping("/hi") // 路由器规则注册
    public Object sayHi() {
    
    
        return "/index.html";
    }

}
  • @RequestMapping(“/web”):路由器规则注册,这个注解一定要有,根据这个注解提供的路径,我们才能访问对应的东西。
  • @RestController:@Controller + @ResponseBody

② 注意

我们之前学过五大类注解,那么这里使用其他类注解是否可以呢?

不行!!!只能用 @Controller 注解

2、@RequestMapping 注解介绍

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

@RequestMapping 即可以修饰类,也可以修饰方法。

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    @RequestMapping("/hi") // 路由器规则注册
    public Object sayHi() {
    
    
        return "Hi,Spring MVC.";
    }

}
  • 当修饰类和⽅法时,访问的地址是类 + ⽅法,例如:http://localhost:8080/web/hi
  • 当修饰⽅法时,访问的地址是⽅法,例如:http://localhost:8080/hi(假设没有修饰类)

3、@RequestMapping 是 post 还是 get 请求?

① GET

@RequestMapping 默认是 get ⽅式的请求,可以使⽤ postman 进⾏测试。

测试一下上面的代码,结果如下:
在这里插入图片描述

② POST

我们还可以通过 @RequestMapping 注解来修改为 POST 请求,代码如下:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

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

}

postman 测试结果如下:
在这里插入图片描述
但如果我们测试 GET 方法,就会报错:
在这里插入图片描述

4、@GetMapping 和 @PostMapping

在学习 @RequestMapping 注解的时候,我们了解到,可以用 method 这个参数来设置请求方式,但是这种方式比较繁琐,有没有更简单的方法呢?

@GetMapping 和 @PostMapping 注解就应运而生了,@GetMapping 注解表示 GET 请求,@PostMapping 注解表示 POST 请求。

	// 两者选其一,否则按最先注册的请求方式执行
	@PostMapping("/hi")
    @GetMapping("/hi")
    public Object sayHi() {
    
    
        return "Hi,Spring MVC.";
    }

下面,我们总结一下 GET 和 POST 请求的写法:

GET:

// @RequestMapping 注解默认为 GET 请求
@RequestMapping("/hi")

// 通过 @RequestMapping 注解的 method 属性声明为 GET 请求
@RequestMapping(value = "/hi",method = RequestMethod.GET)

// 使用 @GetMapping 注解
@GetMapping("/hi")

POST:

// 通过 @RequestMapping 注解的 method 属性声明为 POST 请求
@RequestMapping(value = "/hi",method = RequestMethod.POST)

// 使用 @PostMapping 注解
@PostMapping("/hi")

三、获取参数

1、传递单个参数

① Request 对象

我们之前学习过 servlet 的传递参数,用 request 方式获取;在 Spring MVC 中,我们同样可以,用 request 方式获取。

在 Spring MVC 中,默认内置隐藏了两个参数,Request 和 Response 对象;如果想要使用这两个参数,只需要在方法中声明即可。代码如下:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    @GetMapping("/hi")
    public Object sayHi(HttpServletRequest request, HttpServletResponse response) {
    
    
        return "Hi,"+request.getParameter("name");
    }

}

postman 测试结果如下:
在这里插入图片描述

② 直接传参

但是用 request 方式获取,只能传递 String 类型的参数,如果需要强制转化,就需要考虑空指向异常的问题,而且还很麻烦。实际上,在 Spring MVC 中,我们可以直接用方法中的参数进行传参,代码如下:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    /**
     * 获取单个参数
     * @param name
     * @return
     */
    @GetMapping("/get1")
    public String getParm1(String name) {
    
    
        return "Hi," + name;
    }

}

postman 测试结果如下:
在这里插入图片描述

2、传递多个参数(非对象)

和传递单个参数相同,直接传参可以了,代码如下:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    /**
     * 获取多个参数
     *
     * @param name
     * @param age
     * @return
     */
    @GetMapping("/get1")
    public String getParm1(String name, Integer age) {
    
    
        return "Hi,name:" + name + " | age:" + age;
    }

}

postman 测试结果如下:
在这里插入图片描述

注意:这里是以 参数名 进行参数匹配的,与参数的顺序无关!

3、传递对象

我们刚刚学习了传递多个参数,但是这样维护起来就很麻烦,所以可以采用传递对象的方式,这样我们只需要维护一个对象即可。

示例:
先新建一个 Student 类:

@Data
public class Student {
    
    
    private Integer id;
    private String name;
    private Integer age;
}

接口如下:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    /**
     * 传递对象
     * @param student
     * @return
     */
    @GetMapping("/get3")
    public String getParm3(Student student) {
    
    
        return student.toString();
    }
}

postman 测试结果如下:
在这里插入图片描述

4、表单参数传递

① 传递多个参数

写一个简单的登录页面 login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <form method="get" action="/web/login">
    <div>
      <h1> 登录 </h1>
      用户:<input name="name"><br>
      密码:<input name="password"><br>
      <input type="submit" value=" 提 交 ">
    </div>
  </form>
</body>
</html>

接口代码:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    /**
     * 表单参数传递
     * @param name
     * @param password
     * @return
     */
    @RequestMapping("/login")
    public String login(String name, String password) {
    
    
    	// 这里参数较少,就直接传参了,一般情况下是传递对象
        return "<h1>用户名:" + name + " | 密码:" + password + "</h1>";
    }
}

访问网页 http://localhost:8080/login.html:
在这里插入图片描述
随便输入数据点击提交,结果如下:
在这里插入图片描述

② 封装为对象

要传递的 User 类:

@Data
public class User {
    
    
    private String name;
    private String password;
}

简单的前端页面 reg.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<form method="get" action="/web/reg">
    <div>
        <h1> 注册 </h1>
        用户:<input name="name"><br>
        密码:<input name="password"><br>
        <input type="submit" value=" 提 交 ">
    </div>
</form>
</body>
</html>

接口代码:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    /**
     * 表单参数传递(对象参数)
     * @param user
     * @return
     */
    @RequestMapping("/reg")
    public String req(User user) {
    
    
        return user.toString();
    }
}

访问网页 http://localhost:8080/reg.html:
在这里插入图片描述
随便输入数据点击提交,结果如下:
在这里插入图片描述

5、后端参数重命名

某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不⼀致,可以使⽤ @RequestParam 来重命名前后端的参数值。

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
	 * 使用 @RequestParam 注解重命名
     * @param username
     * @return
     */
    @GetMapping("/get4")
    public String getParm1(@RequestParam("name")String username) {
    
    
        return "Hi," + username;
    }
    
}

使用 postman 测试:
在这里插入图片描述

6、设置参数必传 @RequestParam

在使用 @RequestParam 注解的时候,默认参数的必传的,如果前端没有传递相应的参数,就会出错,所以我们还需要设置一下参数为非必传,这个使用 @RequestParam 注解的 required 属性即可。

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 使用 @RequestParam 注解设置参数非必传
     * @param username
     * @return
     */
    @GetMapping("/get5")
    public String getParm5(@RequestParam(value = "name",required = false) String username) {
    
    
        return "Hi," + username;
    }
    
}

使用 postman 测试:
在这里插入图片描述

7、@RequestBody 接收JSON对象

① postman 传递 JSON 对象

在传参之前,我们先来了解一下如何使用 postman 传递 JSON 对象:
在这里插入图片描述
然后在下面按照 JSON 的格式写即可:
在这里插入图片描述

② 错误的传递

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

    @RequestMapping("/login2")
    public HashMap<String,Object> login2(String name, String password) {
    
    
        HashMap<String,Object> result = new HashMap<>();
        result.put("name",name);
        result.put("password",password);
        return result;
    }

    @RequestMapping("/login3")
    public HashMap<String,Object> login3(User user) {
    
    
        HashMap<String,Object> result = new HashMap<>();
        result.put("name",user.getName());
        result.put("password",user.getPassword());
        return result;
    }
}

分别用 postman 测试:
login2接口在这里插入图片描述
login3接口在这里插入图片描述
我们可以看到,明明我们传递的是 JSON 对象,但是却无法接收,这是为什么呢?这是因为在 Spring MVC 中,需要用到 @RequestBody 注解来传递 JSON 对象参数。

③ @RequestBody

接口代码:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 传递 JSON 对象
     * @param user
     * @return
     */
    @RequestMapping("/login3")
    public HashMap<String,Object> login3(@RequestBody User user) {
    
    
        HashMap<String,Object> result = new HashMap<>();
        result.put("name",user.getName());
        result.put("password",user.getPassword());
        return result;
    }
    
}

使用 postman 测试:
在这里插入图片描述
这里我们就获取到了 JSON 对象。

注意:@RequestBody 注解拿到的一定是一个对象,不能是属性!!!

8、获取URL中参数 @PathVariable

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 使用 @PathVariable 注解 获取 URL 中参数
     * @param name
     * @param password
     * @return
     */
    @GetMapping("/get6/{name}/{password}")
    public String getParm6(@PathVariable String name, @PathVariable String password) {
    
    
        return "Hi," + name + ": " + password;
    }
    
}

使用 postman 测试:
在这里插入图片描述

9、上传文件@RequestPart

① postman 传递文件

在传参之前,我们先来了解一下如何使用 postman 传递文件:
在这里插入图片描述
postman
在这里插入图片描述

② @RequestPart

测试接口:

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 上传文件
     * @param name
     * @param file
     * @return
     * @throws IOException
     */
    @RequestMapping("/upload")
    public String upload(String name, @RequestPart("picture") MultipartFile file) throws IOException {
    
    
        // 保存文件
        file.transferTo(new File("E:\\work\\img.pmg"));
        return "success";
    }
}

使用 postman 测试:
在这里插入图片描述
前往 E:\work 查看 img.pmg 是否存在:
在这里插入图片描述

③ 获取当前项目的绝对路径

ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getPath();
new ClassPathResource("").getFile().getAbsolutePath();
ClassUtils.getDefaultClassLoader().getResource("").getPath();
ResourceUtils.getFile("classpath:static/").getPath();

10、获取Cookie/Session/header

① Cookie

Ⅰ. 增加 Cookie

在网页中,F12 打开开发者工具:
在这里插入图片描述

Ⅱ. 传统获取

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 传统方法获取 Cookie
     * @param request
     * @param response
     * @return
     */
	@RequestMapping("/cookie")
    @ResponseBody
    public String cookie(HttpServletRequest request, HttpServletResponse response) {
    
    
        String name = request.getParameter("name");
        Cookie[] cookies = request.getCookies();
        return "Hi," + name;
    }

}

Ⅲ. @CookieValue

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 使用 @CookieValue 注解
     * @param name
     * @return
     */
    @RequestMapping("/cookie2")
    @ResponseBody
    public String cookie2(@CookieValue("name") String name) {
    
    
        return "name: " + name;
    }

}

使用 网页 测试:
在这里插入图片描述

② header

Ⅰ. 传统获取

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 传统方法获取 Header
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/header")
    @ResponseBody
    public String header(HttpServletRequest request, HttpServletResponse response) {
    
    
        String name = request.getParameter("name");
        String userAgent = request.getHeader("User-Agent");
        return "Hi," + name + ": " + userAgent;
    }

}

使用 postman 测试:
在这里插入图片描述

Ⅱ. @RequestHeader

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 使用 @RequestHeader 注解
     * @param userAgent
     * @return
     */
    @RequestMapping("/header2")
    @ResponseBody
    public String header2(@RequestHeader("User-Agent") String userAgent) {
    
    
        return "Hi," + userAgent;
    }

}

使用 postman 测试:
在这里插入图片描述

③ Session

Ⅰ. 创建 Session

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 创建 Session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/setsession")
    @ResponseBody
    public String session(HttpServletRequest request, HttpServletResponse response) {
    
    
    	// 是否必须,是,如果没有就创建一个 session
        HttpSession session = request.getSession(true);
        if(session!=null){
    
    
            session.setAttribute("username","wangwu");
        }
        return "success";
    }
    
}

Ⅱ. 传统获取

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 传统方法获取 Session
     *
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/session")
    @ResponseBody
    public String session(HttpServletRequest request, HttpServletResponse response) {
    
    
        // 如果 session 不存在,不会⾃动创建
        HttpSession session = request.getSession(false);
        String username = "暂⽆";
        if (session != null && session.getAttribute("username") != null) {
    
    
            username = (String) session.getAttribute("username");
        }
        return "username:" + username;
    }
    
}

使用 postman 测试:
在这里插入图片描述

Ⅲ. @SessionAttribute

@RestController
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 使用 @SessionAttribute 注解
     *
     * @param username
     * @return
     */
    @RequestMapping("/session2")
    @ResponseBody
    public String session2(@SessionAttribute(value = "username", required = false) String username) {
    
    
        return "username:" + username;
    }
    
}

使用 postman 测试:
在这里插入图片描述

四、返回数据

1、返回静态页面

先创建一个 html 页面:
在这里插入图片描述

@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 返回 静态⻚⾯
     * @return
     */
    @RequestMapping("/retindex")
    public Object retindex(){
    
    
        return "/index.html";
    }
    
}

访问网址:http://localhost:8080/web/retindex
在这里插入图片描述

2、返回 text/html

@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 返回 html
     * @return
     */
    @RequestMapping("/rethtml")
    @ResponseBody
    public Object rethtml(){
    
    
        return "<h1>Hello~</h1>";
    }
    
}

访问网址:http://localhost:8080/web/rethtml
在这里插入图片描述

3、返回 JSON 对象

@Controller // 在 Spring 启动的时候,加载并注册
@RequestMapping("/web") // 路由器规则注册
public class WebController {
    
    

	/**
     * 返回 JSON
     * @return
     */
    @RequestMapping("/retjson")
    @ResponseBody
    public HashMap<String, String> retjson() {
    
    
        HashMap<String, String> map = new HashMap<>();
        map.put("zhangsan", "123");
        map.put("lisi", "666");
        map.put("wangwu", "777");
        return map;
    }
    
}

访问网址:http://localhost:8080/web/retjson
在这里插入图片描述

4、请求转发或请求重定向

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

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

① 转发和重定向的区别

@Controller
public class TestController {
    
    

    /**
     * 请求转发
     * @return
     */
    @RequestMapping("/hello")
    public Object hello(){
    
    
        return "forward:/index.html";
    }

    /**
     * 请求重定向
     * @return
     */
    @RequestMapping("/hello2")
    public Object hello2(){
    
    
        return "redirect:/login.html";
    }
}

打开网址:http://localhost:8080/hello
在这里插入图片描述

打开网址:http://localhost:8080/hello2
在这里插入图片描述

我们可以看到,转发的地址还是原地址,但重定向的地址发生了改变!

forward 和 redirect 具体区别如下:

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

② 举例说明

forward(请求转发)和 redirect(请求重定向)的区别,举例来说,例如,你告诉你妈妈,你想吃辣条,如果你妈妈,说好,我帮你去买,这就是 forward 请求转发;如果你妈妈让你⾃⼰去买,那么就是请求 redirect 重定向。

5、@ResponseBody 说明

  • @ResponseBody 返回的值如果是字符会转换成 text/html,如果返回的是对象会转换成 application/json 返回给前端。
  • @ResponseBody 可以⽤来修饰⽅法或者是修饰类,修饰类表示类中的所有⽅法都会返回 html 或者 json,⽽不是视图。

6、查看更多注解

https://docs.spring.io/springframework/docs/current/reference/html/web.html#mvc-ann-requestmapping

猜你喜欢

转载自blog.csdn.net/WZRbeliever/article/details/128321199