赞
踩
哈哈哈,祝自己生日快乐鸭~
目录
①官网定义译为中文:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,从一开始就包含在 Spring 框架中。它的正式名称“Spring Web MVC”来自其源模块的名称(Spring-webmvc),但它通常被称为“Spring MVC” 。我们可以由上述定义,得到两个点:a.Spring MVC是一个web框架b.Spring MVC是基于Servlet API来进行构建的②什么是MVC?MVC:Model View Controller翻译中文就是“模型,视图,控制器”,它是一种设计模式,这种设计模式将软件(项目)分为三部分:模型,视图和控制器。(需要注意的是视图一般分为服务器视图和客户端视图,而在这里我们所说的视图指的是服务器视图)③MVC和Spring MVC的关系:
MVC是一种设计思想,而Spring MVC更可以说是它的一种实现(一种具体的实现框架)
④用自己的理解来谈谈Spring MVC:
Spring MVC是一个基于MVC设计模式和Servlet API实现的Web项目,同时Spring MVC又是Spring框架中的一个Web模块,它是随着Spring诞生而存在的一个框架
之所以要学习 Spring MVC 是因为它是⼀切项目的基础,我们以后创建的所有 Spring、Spring Boot 项目基本都是基于 Spring MVC 的。
换句话说可以说是我们需要掌握的方法:
①实现用户和程序的映射(用户在URL输入地址之后,能够在程序里找到相应的方法)
②服务器端要得到用户的请求参数
③服务器端要将结果返回给用户(前端)
下面将依次对这几个板块进行介绍
创建一个Spring MVC项目实质上就是创建一个Spring Boot项目,在配置中选取引入MVC即可。图解步骤如下:(前面Spring Boot创建之前有写过,这里就不作重复了)
实现用户和程序的映射主要有以下三种方法
①用法:
@RequestMapping(“/xxx”)
既可以用于类上,也可以放于方法上,访问地址就是类地址+方法地址
②示例:
a.我们随意创建一个页面来访问:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController1 { @ResponseBody//返回一个非静态页面 @RequestMapping("/hello") public String sayhi(){ System.out.println("hello spring mvc"); return "hello spring mvc"; } }结果如下:
b.我们能够知道直接通过url访问的,那么必然是get请求,我们来抓一下包,看看自己的判断是否是正确的:
我们可以发现确实是get请求,那么要是我们用post请求来完成是否可以呢?
我们用postman来进行测试一下:
我们就发现默认情况下,@RequestMapping既可以支持get请求,又可以支持post请求 。但是,我们仍然可以对参数进行拓展
c.@RequestMapping参数拓展:(让其只支持一种访问方式,我们这里以post为例)
package com.example.demo; 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; @Controller public class UserController1 { @ResponseBody @RequestMapping(method = RequestMethod.POST,value = "/hello") public String sayhi(){ System.out.println("hello spring mvc"); return "hello spring mvc"; } }我们现在可以看到参数里已经指定了method为post,这个时候我们显然是不能够通过URL来访问的,因此,我们用postman来测试现在它支持的形式:
(1)当为post的时候,如预期,没有问题
这个时候我们抓包fiddler也是得到同样的情况:
(2)当为GET的情况:
我们会发现这样就出现了问题。那么也就是这种指定方式是只能支持指定的一种 。
当然,指定为某种,我们也可以采用更简单的如下方式
①用法:
@GetMapping(“/xxx”)
②示例:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController1 { @ResponseBody @GetMapping("/hello") public String sayhi(){ System.out.println("hello spring mvc"); return "hello spring mvc"; } }结果如下:
①用法:
@PostMapping(/xxx”)
②示例:(POST是无法直接通过URL访问到的,我们需要通过postman来进行测试)
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; @Controller public class UserController1 { @ResponseBody @PostMapping("/hello") public String sayhi(){ System.out.println("hello spring mvc"); return "hello spring mvc"; } }结果如下:
①解释:
直接在方法中传入一个参数
②示例:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController2 { @ResponseBody @RequestMapping("/getuserid") public Student student(Integer id){//这里必须使用包装类,否则会报错 Student student=new Student(); student.setId(1); student.setName("张三"); student.setAge(18); student.setPassword("123456"); return student; } }结果如下:
③注意!!
此传递名称需要与前端传递的产生名保持一致,否则就获取不到参数的值。如下:
①说明:
顾名思义就是传递多个参数
②示例:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController2 { @ResponseBody @RequestMapping("/getuserid") public String student(Integer id,String name){//这里必须使用包装类,否则会报错 Student student=new Student(); student.setId(1); student.setName("张三"); student.setAge(18); student.setPassword("123456"); return "id: " + id+ " | name: " + name; } }结果如下:
当参数非常多的时候,显然这个时候代码的可读性就大大降低了,所以我们为了增强代码的可读性,我们决定使用传递对象。
①说明:
传递对象顾名思义是对整个对象来进行封装传递
②示例:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController3 { @ResponseBody//返回一个非静态页面 @RequestMapping("/object") public String reg(Student student){ return "学生的基本信息"+student; } }输出结果:
注意:
虽然我们在代码中传递的是对象,但是不要忘记,在url中我们还是应该输入需要参数的值,否则就会出现为null的如下情况
某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可能不一致,比如前端传递了一个username给后端,而后端又是name字段来接收的,这样就会出现参数接收不到的情况,如果出现这种情况,我们就可以使用@RequestParam来重命名前后端的参数值。
①示例前后端不一致时会出现的错误:
而有时候面临这个情况,前后端都不愿意选择让步,所以我们引入@RequestParam来进行处理
②引入后处理:
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController2 { @ResponseBody @RequestMapping("/getuserid") public String student(@RequestParam("username") String name){//这里必须使用包装类,否则会报错 Student student=new Student(); student.setId(1); student.setName("张三"); student.setAge(18); student.setPassword("123456"); return "name: " + name; } }输出结果:(如果有多个参数需要改名,就用多个@RequestParam即可)
③注意:当采用了@RequestParam后,要是不传参数就会报错如下:
而当没有这个注解的时候,没传参数就会默认为null如下:
④解决③中当有@RequestParam注解不传参时报错的情况:
(我们会发现在默认情况下,一定要传参数,否则就会报错)
如果想要解决此问题,可以给@RequestParam里面添加required=false,这样不传参数就也不会报错
package com.example.demo; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController2 { @ResponseBody @RequestMapping("/getuserid") public String student(@RequestParam(name="username",required = false) String name){//这里必须使用包装类,否则会报错 Student student=new Student(); student.setId(1); student.setName("张三"); student.setAge(18); student.setPassword("123456"); return "name: " + name; } }结果如下:
如果需要接收json格式的对象,那么我们就必须添加@RequestBody这个注解
①未添加@RequestBody注解的情况:
我们用fiddler来进行抓包,来看这个是什么形式:
可以看出此时并不是json格式的,这个的输出结果是这样:
②当我们加了@RequestBody后的情况:
这个时候我们访问fiddler,也可以看到现在的类型究竟是什么:
①此处URL中的参数的含义:
直接拿URL地址中的参数,简单来说,就是从URL中
?
前面的字段中获取参数。举个例子:
②为什么要获取URL中的参数?
因为某些软件或者游戏为了增加曝光度的话,当我们搜索其角色或者是内容名字,要是它加在?后的话,曝光率相比于加在?前会大大降低,所以更多的商家,就将其参数放于?前的URL中。
③格式:
a.在@RequestMapping(“/xxx/{参数1}{参数2}”)
b.在方法中加上@PathVariable注解
④示例如下:
package com.example.demo; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class UserController4 { @ResponseBody @RequestMapping("/getThing/{id}/{name}") public String getThing(@PathVariable Integer id,@PathVariable String name){ return "id:"+id+"name:"+name; } }这样当我们在URL里输入id为1,name为小乔时,就会出现如下结果:
①格式:
用@RequestPart注解
②示例:保存路径写死的情况
package com.example.demo; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; @Slf4j @Controller @ResponseBody //返回一个非静态页面 public class UserController5 { //上传文件 @RequestMapping("/upimg") public boolean upImg(Integer id, @RequestPart("img") MultipartFile file) { boolean result = false; //保存文件到本地目录 try { file.transferTo(new File("C:\\zhuomian\\222.png")); result = true; } catch (IOException e) { log.error("上传图片失败" + e.getMessage()); } return result; } }我们用postman来看示例是否成功:
然后我们会发现在桌面上多了一个222.png
而在实际开发中,我们的保存路径却并没有写死,所以我们要用更符合实际开发的来写:
②保存路径不写死的情况:
a.因为在公司中会涉及不同的测试,开发环境,运行环境等等,然而当环境改变的时候,为了使我们更加方便,所以我们引入相应的配置,最终的时候,只需要修改一行配置,就可以完成切换。如下,我们设置三个yml配置文件。
我们这里就用yml文件来进行演示,需要注意的是,前面的application是固定的,我们只需要更改后面的名称即可。
(1)主配置文件
application.yml
中来配置配置文件的运行平台
# 设置配置文件的运行平台 spring: profiles: active: xxx # 如运行application-dev配置文件 即active: dev(2)在不同的环境下配置不同的参数,如在开发配置文件中配置图片保存路径:
# 文件保存路径 img: path: C:\\zhuomian\\b.而在这种情况下,我们要保存图片到任意路径的话,需要操作以下几步:
(1)配置并获取保存的路径
(2)利用(UUID)来保持图片名称的唯一性
(在此步要获取到名片的格式,并且将UUID与图片的格式拼接在一起)
(3)储存图片
代码如下:
package com.example.demo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.util.UUID; @Slf4j @Controller @ResponseBody //返回一个非静态页面 public class UserController5 { //获取配置文件的保存路径 @Value("${img.path}") private String imgpath; //上传文件 @RequestMapping("/upimg") public boolean updateImg(Integer id, @RequestPart("img") MultipartFile file) { boolean result = false; //得到原图片的名称 String filename = file.getOriginalFilename(); //得到图片后缀(png) String fixType = filename.substring(filename.lastIndexOf(".")); //生成不重名的文件名 filename = UUID.randomUUID().toString() + filename; try { //将图片保存 file.transferTo(new File(imgpath + filename)); result = true; } catch (IOException e) { log.error("图片上传失败!" + e.getMessage()); } return result; } }postman来测试:
测试结果如下:
测试成功
目录少写了cookie,header,session的获取,下期我们再补上哦,顺便把MVC内容讲完
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。