作者:~小明学编程
文章专栏:JavaEE
格言:热爱编程的,终将被编程所厚爱。
目录
说说为什么好久没有更新文章吧
说起来有些惆怅了,在快手实习了快三个月了,因为学校的一些缘故下周四就要从快手离职了,即将结束我这将近三个月的实习生涯了,学到了很多的东西同时也有一些的不舍,不过咱们还是要向前看的,接下来的一段时间争取在五一假期结束之前把EE的一些框架给学完,然后尝试冲一下提前批,认真备战秋招了。
什么是SpringMVC
所谓的SpringMVC要是按照官方给的文档的话那就是:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从⼀开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来⾃其源模块的名称(Spring-webmvc),但它通常被称为"SpringMVC"。
MVC的定义
MVC 是 Model View Controller (模型视图控制器)的缩写,它是软件⼯程中的⼀种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。
- Model(模型) 是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
- View(视图) 是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的。
- Controller(控制器) 是应⽤程序中处理⽤户交互的部分。通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
- 可以把 View,Controller,Model 看作是一个软件(项目)。
- 然后用户通过浏览器发送一个 HTTP 请求到 Controller ,然后 Controller 完成对数据的校验,校验数据的正确性和合法性。
- Controller 校验数据通过之后,就会将请求数据发送到 model,然后 model 对数据库进行处理之后,再把结果发给 Controller。
- 然后 Controller 在把得到的数据交给 View。
- View 是服务器的视图层,然后和前端的模板相结合,再加上渲染,然后发给客户,客户就能看懂了。
Spring MVC 是⼀个实现了 MVC 模式,并继承了 Servlet API 的 Web 框架。因为是 Web 框架,所以⽤户在浏览器中输⼊了 url 之后,我们的 Spring MVC 项 ⽬就可以感知到⽤户的请求。
创建一个SpringMVC的项目
创建一个人SpringMVC的项目的方式和SpringBoot的方式是一样的。
这里我们需要添加springweb的依赖。
SpringMVC的使用方式
- 实现 用户 和 程序 的映射(在浏览器输入 URL 之后,能够在程序中匹配到相应的方法)
- 服务器端要得到用户的请求参数
- 服务器端要将结果返回给用户(前端)
@RequestMapping实现用户和程序的映射
首先我们在访问服务端的时候我们需要找到我们的路径,SpringMVC中提供了注解来帮助我们更加简单的来完成这样一个过程。
@RequestMapping 映射,可以加在 类上面,就是一级目录,然后方法上面再加的话,就是二级目录。
@Controller
@RequestMapping("/user")
@ResponseBody
public class UserController {
//从配置文件中读取图片的保存路径
@RequestMapping("/sayhi")
public String sayHi() {
return "hello world";
}
}
通常情况下我们默认请求格式是get的请求,但是有时候我们可能会有post形式的请求,这个时候就需要我们去做相应的调整了。
get请求的3种写法
// 写法1
@RequestMapping("/index")
// 写法2
@RequestMapping(value = "/index",method = RequestMethod.GET)
// 写法3
@GetMapping("/index")
post请求的2种写法
// 写法1
@RequestMapping(value = "/index",method = RequestMethod.POST)
// 写法2
@PostMapping("/index")
获取用户请求的参数
@Controller
@ResponseBody
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public String login(String username, String password) {
return "用户名:" + username + " 密码:" + password;
}
}
我们在访问我们的地址的时候只要保证url中的名字与我们方法中的参数名字一样就行了。当然有时候我们前端所给的变量名我们不是很喜欢但是我们又必须要保证前后端的字段一样这个时候我们就需要用@RequestParam注解来改变我们的变量名称。
@RequestMapping("/getuser")
public UserInfo getUserById(@RequestParam(value = "userage",required = false) Integer age) {//改名注解
UserInfo userInfo = new UserInfo();
userInfo.setAge(age==null?0:age);
return userInfo;
}
其中我们可以看到required=false,因为其默认是true的这是因为如果我们不特别说明是false的话,如果在访问的时候没有传这个参数就会报错。
上面我们的请求中都只有两个参数如果我们的参数是三个四个五个或者更多的话那么该怎么办呢?
@RequestBody 接收json对象
@Data
public class UserInfo {
private int age;
private String name;
}
@RequestMapping("/userdome")
public UserInfo userDome(@RequestBody UserInfo userInfo) {//可以以json格式来传参发送请求
return userInfo;
}
@PathVariable从 URL 中获取参数
http://127.0.0.1:8080/user/info/2/zhangsan
类似于这种URL有时候我们也许需要获取里面的参数,比如这个2还有这个zhangsan这个时候我们就需要从这串URL中去获取这些值了。
PathVariable这个注解就可以帮助我们来解决这个问题,使用的时候需要注意我们的参数名称需要和RequestMapping中的名称一致。
@Controller
@ResponseBody
@RequestMapping("/user")
public class UserController {
@RequestMapping("/info/{id}/{name}")
public String getURLInfo(@PathVariable Integer id, @PathVariable String name) {
return "ID:" + id + " name:" + name;
}
}
还需要注意的一点就是我们的RequestMapping中我们需要哪一个字符串那么就要将其用花括号给括起来。
实现上传文件
//从配置文件中读取图片的保存路径
@Value("${img.path}")
private String imgPath;
//上传文件
@RequestMapping("/upimg")
public boolean upLoad(Integer id, @RequestPart("img") MultipartFile multipartFile) {
boolean result = false;
// 1.目录=imgPath
// 2.图片名称(图片不能重复)【UUID】
// 3.获取原上传图片的格式
String fileName = multipartFile.getOriginalFilename();//得到源图片的格式
fileName = fileName.substring(fileName.lastIndexOf("."));
fileName = UUID.randomUUID().toString()+fileName;
try {
multipartFile.transferTo(new File(imgPath+fileName));
log.warn("上传成功");
return true;
} catch (IOException e) {
log.warn("上传失败");
return false;
}
}
这里的@Value可以将将配置文件中的路径进行属性注入。
配置文件的路经
首先先带大家了解一下配置文件,首先就是application.yml这个是固定的用来帮助我们选择到底是用哪一个配置文件,因为在实际的工作中我们可能会有许多的环境比如说生产环境,测试环境还有线上环境,文件名的前缀都是application不同的是后面的后缀所代表的环境不一样。
此时我们的文件就上传成功了 。
获取 Cookie/Session/header
获取Cookie
cookie作为我们记录用户文本的重要的一种方式,很多的时候我们都需要用到cookie。
servlet写法
@RequestMapping("/cookie")
public void getCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();//获取全部的cookie
for (Cookie cookie:
cookies) {
log.info(cookie.getName()+": "+cookie.getValue());
}
}
这个是我们servlet的写法,就是通过getCookie的方法来过去全部的cookie然后听过日志将其打印出来。
@CookieValue写法
@RequestMapping("/cookie2")
public String getCookie2(@CookieValue("id") String cookie) {//使用注解获取cookie
return "cookie:"+cookie;
}
当我们想要获取多个指定的cookie的时候我们就可以添加多个注解和参数。
获取header
header作为我们的请求头里面记录了我们的浏览器或者我们主机的一些信息,因为我们在访问服务器的时候所用的浏览器的版本可以不一样对于不同的版本和不同的机型接受响应渲染可能不一样所以我们有的时候许呀针对不同的浏览器和版本做出不同的响应。
servlet写法
@RequestMapping("userUA")
public String getHead(HttpServletRequest request) {
return "head:" + request.getHeader("User-Agent");
}
@RequestHeader
@RequestMapping("userUA2")
public String getHead2(@RequestHeader("User-Agent") String userAgent) {
return "User-Agent;"+userAgent;
}
存储/获取session
存储session
//存储session
@RequestMapping("/session")
public boolean setSession(HttpServletRequest request) {
boolean result = false;
//1.得到session
HttpSession session = request.getSession(true);//如果没有就创建一个session
session.setAttribute("aaa","bbb");
result = true;
return result;
}
对于存储session我们只能通过HttpServletRequest的方式来完成,然后通过相应的方法来获取。
获取session
//获取session
@RequestMapping("getsession")
public String getSession(HttpServletRequest request) {
String result = null;
HttpSession session = request.getSession(false);
if (session!=null&&session.getAttribute("aaa")!=null) {
result = (String) session.getAttribute("aaa");
}
return result;
}
//获取session
@RequestMapping("getsession2")
public String getSession2(@SessionAttribute(value="aaa",required = false) String session) {
return "会话"+session;
}
我们可以选择用传统的servlet方式来获取session也可以使用@SessionAttribute注解来更简单的获取到session。
返回数据
通过前面的学习我们知道我们默认的返回是视图也就是一个静态的页面,但是现在我们的前后端分离了,我们在返回结果的时候往往返回的是单纯的数据,这个时候就需要我们去根据情况去调整了。
@RequestMapping("sayhi")
public String sayHi() {
return "hello.html";
}
可以看到此时我们返回的就是一个前端的页面。
@ResponseBody
@RequestMapping("sayhi")
public String sayHi() {
return "hello.html";
}
在我们加了@ResponseBody注解之后此时我们返回的就是就是单纯的字符串了。
@RestController
@RestController相当于是@Controller 和@ResponseBody的结合体。
请求转发与请求重定向
请求转发
//请求转发
@RequestMapping("fw")
public String fw() {
return "forward:/hello.html";
}
请求转发是让我们的服务器将我们的请求转发给下一个地址。
请求重定向
//请求重定向
@RequestMapping("rd")
public String rd() {
return "redirect:/hello.html";
}
请求重定向则是让我们的浏览器将我们的新的地址发给服务器。
请求转发与请求重定向的区别
forward 和 redirect 具体区别如下:
1. 请求重定向(redirect)将请求重新定位到资源;请求转发(forward)服务器端转发。
2. 请求重定向地址发⽣变化,请求转发地址不发⽣变化。
3. 请求重定向与直接访问新地址效果一致,不存在原来的外部资源不能访问;请求转发服务器端转发有可能造成原外部资源不能访问。
前后端交互
form表单形式
<!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>计算器示例</title>
</head>
<body>
<form action="/calc">
<h1>计算器</h1>
数字1:<input name="num1" type="text"><br>
数字2:<input name="num2" type="text"><br>
<input type="submit" value=" 点击相加 ">
</form>
</body>
</html>
@RestController
public class CalcController {
@RequestMapping("calc")
public String calc(Integer num1,Integer num2) {
if (num1==null||num2==null) return "<h1>参数错误!</h1><a href='javascript:history.go(-1);'>返回</a>";
return "<h1>计算结果为:"+(num1+num2)+"</h1><a href='javascript:history.go(-1);'>返回</a>";
}
}
Ajax形式
<!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">
<script src="js/jquery.min.js"></script>
<title>Document</title>
<script>
//ajax 提交
function mysub(){
//1.判空 也可以把 jQuery 符号换成 $
var username = jQuery("#username");
var password = jQuery("#password");
//使用 trim 方法来去掉空格
if(jQuery.trim(username.val())==""){
alert("请先输入用户名!");
//把光标重新放到元素上面
username.focus();
return;
}
if(jQuery.trim(password.val())==""){
alert("请先输入密码!");
password.focus(); //光标重制到此元素
return;
}
jQuery.ajax({
url:"/user/login2",
type:"POST",
data:{"username":username.val(),
"password":password.val()},
success:function(result){
alert(JSON.stringify(result));
}
});
}
</script>
</head>
<body>
<div style="text-align: center;">
<h1>登录</h1>
用户:<input id="username">
<br>
密码:<input id="password" type="password">
<br>
<input type="button" value=" 提交 " onclick="mysub()" style="margin-top: 20px;margin-left: 50px;">
</div>
</body>
</html>
@RequestMapping("/login2")
public HashMap<String, Object> login2(String username, String password) {
HashMap<String, Object> result = new HashMap<>();
int state = 200;
int data = -1;//等于 1 的话,就表述登陆成功
String msg = "";
if (StringUtils.hasLength(username) && StringUtils.hasLength(password)) {
if (username.equals("admin") && password.equals("admin")) {
data = 1;
msg = "";
}
} else {
msg = "非法参数";
}
result.put("state", state);
result.put("data", data);
result.put("msg", msg);
return result;
}