04、Spring MVC

打印 上一主题 下一主题

主题 874|帖子 874|积分 2622

Spring MVC是Spring的Web模块,用来开发Web应用的,它最终作为B/S、C/S模式下的Server端
Web应用的核心就是处置处罚HTTP哀求并响应。
一、关于两种开发模式说明

我们使用Spring MVC有两个开发模式


  • 前后分离(数据与页面分离)
         
    • @ResponseBody   
    • @RestController   
    • 其涉及的生要机制是:序列化(对象 -> 串)、反序列化(串 -> 对象)  

  • 前后不分离(页面由服务端进行渲染)
         
    • 转发   
    • 重定向  

后面我们对这些内容都会做详细的说明
二、入门案例

新建模块:springmvc-01-helloword
前提:我们使用脚手架搭建的是SpringBoot项目!
pom文件中添加如下依赖
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
复制代码
新增Controller类:HelloController
  1. @Controller // 告诉spring这是一个控制器(用来处理请求)
  2. public class HelloController {
  3.     @ResponseBody   // 把返回值放到响应体当中
  4.     @RequestMapping("/hello")
  5.     public String handle() {
  6.         return "Hello,SpringMVC! 你好!~~~";   // 默认返回值是跳转到一个页面
  7.     }
  8. }
复制代码
此时我们运行脚手架,欣赏器访问地点:http://localhost:8080/hello,可以看到欣赏器页面上输出文本信息 Hello,SpringMVC!你好!~~~~
三、对哀求的处置处罚

@RequestMapping

通配符

这个注解称为路径映射注解,可以使用得某一个方法与一个路径进行绑定,以后收到一个哀求时它的路径规则与之匹配时就会对应的使用这个绑定的方法进行处置处罚。
路径规则:在路径位置是可以使用通配符的
*:匹配任意多个字符
**:匹配多层路径
?:匹配任意单个字符,有且必须有一个
关于通配符的一些注意点:


  • ? 必须要有且仅有一个字符,没有不行多了也不行!不可以匹配/
  • 如果我们哀求的路与一个没有带通配符的映射匹配并且也与一个带了通配符的映射匹配则优先匹配那个不带通配符的,这个是精确匹配到的,所以精确匹配优先级高于模糊匹配
  • * 可以匹配0~N个字符,但是不可以匹配/,因为/是哀求路径分割符
  • 当*与?的匹配都可以匹配上的时间优先匹配?的
  • 精确匹配的优先级:完全匹配 > ?> * > **
  • ** 通配符可以匹配多层路径,它只能放在最后,而*却是可以放到字符中间的
  • ** 它就是为了匹配多层路径的只能写在最后/**
  • 对于都是精确的哀求路径映射绑定了多个方法的时间启动项目会报错,精确路径必须要全局唯一
哀求限定

我们来说哀求限定前先看看@RequestMapping的界说
  1. @Target({ElementType.TYPE, ElementType.METHOD})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Mapping
  5. @Reflective({ControllerMappingReflectiveProcessor.class})
  6. public @interface RequestMapping {
  7.     String name() default "";
  8.     @AliasFor("path")
  9.     String[] value() default {};
  10.     @AliasFor("value")
  11.     String[] path() default {};
  12.     RequestMethod[] method() default {};
  13.     String[] params() default {};
  14.     String[] headers() default {};
  15.     String[] consumes() default {};
  16.     String[] produces() default {};
  17. }
复制代码
这个注解中属性name,value,path都是指的同一个东西(映射的路径)
method属性
它用来指定哀求的方法
哀求的方法有:GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS,TRACE
如果哀求的路径匹配,但是哀求的方法不匹配会报错405 Method Not Allowed
如下示例:我们要求test01这个方法绑定的哀求路径/test01只能是DELETE或者是GET哀求
  1. @RequestMapping(value = "/test01", method = {RequestMethod.DELETE,RequestMethod.GET})
  2. public String test01() {
  3.     return "test01";
  4. }
复制代码
params属性
它用来指定哀求参数


  • 写法一:params="username" 表现必须要带有username参数,详细哀求时携带的值是什么不关心
  • 写法二:params="age=18" 表现必须要带上一个参数age,并且哀求时携带的值是18
  • 写法三:params="gender!=1"  表现给定的参数gender值不可以为1,注意,这个时间如果哀求没有gender参数也表现不为1,也是可行的
  • 写法四:params={"username=admin","age","gender!=1"} 一次可以指定多个参数规则
  • 写法五:params="!username"  表现不可以携带username这个参数
如果哀求时,哀求参数不匹配会返回400错误 Bad Request
如下例所示:
  1. @RequestMapping(value = "/test02", params = {"username=admin", "age", "gender!=1"})
  2. public String test02() {
  3.     return "test02";
  4. }
复制代码
headers属性
它的写法与params的写法是一样的,只不过它匹配是针对的哀求头中的内容
如果哀求头不匹配则会返回404错误 Not Found
如下例所示:
  1. @RequestMapping(value = "/test03", headers = "haha")
  2. public String test03() {
  3.     return "test03";
  4. }
复制代码
consumes属性
这个属性用来限定哀求内容类型
consumes="application/json" 表现哀求的内容类型为application/json
如果哀求内容类型不匹配会返回415错误 Unsupported Media Type
如下例所示:
  1. @RequestMapping(value = "test04",consumes = "application/json")
  2. public String test04() {
  3.     return "test04";
  4. }
复制代码
produces属性
这个属性用来限定响应类型
produces="text/html;charset=utf-8"  指定向欣赏器响应的类型
如下例所示:
  1. @RequestMapping(value = "/test05",produces = "text/html;charset=utf-8")
  2. public String test05() {
  3.     return "<h1>你好,张三</h1>";
  4. }
复制代码
关于HTTP


对于web模型来说就是哀求与响应,在哀求与响应之间数据互换都是使用的HTTP
哀求

哀求的结构:


  • 哀求首行:包含 哀求方式,哀求路径,哀求协议
  • 哀求头:key: value(有多个key: value,每一对占一行)
  • 哀求体:对于get哀求来说,哀求参数会携带在哀求路径上,post哀求的哀求参数会放在哀求体中
HTTP的默认端标语是:80
HTTPS的默认端标语是:443
get哀求与post哀求对比:


  • get哀求参数附带在欣赏地点上以明文展示,不安全;post哀求参数放在哀求体当中相对安全一点
  • 哀求路径长度是有限制的,使用get哀求参数过长必要使用post来哀求
  • 对于类似于文件上传这种哀求,数据无法携带在地点栏上,必要使用post哀求
  • get哀求一般用来查询服务器中的资源,而不对资源进行变更,post哀求则一般是提交资源到服务器可能会导致资源的变更
哀求头中有很多重要的信息,使用Spring MVC可以快速地获取到它们
哀求体中携带大量的数据,特殊是post哀求,会把哀求的参数放到哀求体当中

JSON数据格式

JSON:JavaScript Objecet Notation(JavaScript对象表现法)
它用于把结构化的数据表现为JavaScript对象的尺度格式,常常用于在网站上表现和传输数据
JSON可以作为一个对象或者字符串存在


  • 作为对象用于解读JSON中的数据,作为字符串用于在网络上传输
  • JavaScript提供了一个全局可访问的JSON对象来对这两种数据进行转换
JSON是一种纯数据格式,它只包含属性,没有方法的
注:把字符串转为原生对象叫做反序列化;把原天生象转为可以通过网络传输的字符串叫做序列化
哀求数据的吸收

普通变量收集哀求

如下所示
  1. // 请求参数:username=zhangsan&password=123456&cellphone=12345678909&agreement=on
  2. @RequestMapping("/handle01")
  3. public String handle01(String username,String password,String cellphone,boolean agreement) {
  4.     System.out.println("handle01()方法执行了!");
  5.     System.out.println("username="+username+",password="+password+",cellphone="+cellphone+",agreement="+agreement);
  6.     return "ok";
  7. }
复制代码
处置处罚方法中的参数保持与哀求提交过来的参数对应


  • 如果我们的哀求参数中没有某个参数,那么处置处罚方法中把这个参数封装为默认值
  • 如果哀求参数中名称与方法的参数名能匹配上则直接封装上
注意:使用这种方式来吸收哀求参数的值要求方法中的参数名要与哀求的参数名保持一致!!
使用@RequestParam注解

这个注解要写在方法参数上,如下所示
  1. @RequestMapping("/handle02")
  2. public String handle02(@RequestParam("username") String name,
  3.                        @RequestParam("password") String pwd,
  4.                        @RequestParam("cellphone") String phone,
  5.                        @RequestParam("agreement") boolean ok) {
  6.     System.out.println("handle02()方法执行了!");
  7.     System.out.println("username="+name+",password="+pwd+",cellphone="+phone+",agreement="+ok);
  8.     return "ok";
  9. }
复制代码
这个时间客户端提交的哀求参数至少要有@RequestParam中指定的这四个参数,当然比它多是没有问题的,如果少了就会报400错误 Bad Requet
如果其中某个参数不是必须的,也就是说客户端可能不传也可能传这个参数,这个时间可以在@RequestParam上指定一个属性required=false,表现这个哀求参数可有可无,如下所示
@RequestParam(value = "agreement",required = false) boolean ok
这个时间哀求参数:agreement 不是必须的,客户端可以不传
如果我们在没有传某个哀求参数时,又不希望处置处罚方法中的参数被赋值为默认值,想让我们的要求同赋值,则可以在@RequestParam中再加上一个属必 defaultValue="指定默认值",如下所示:
@RequestParam(value = "password",required = false,defaultValue = "123456") String pwd
这个时间哀求参数password没有传的时间,pwd参数不会被赋默认的null,而是会赋值“123456”
注意:一旦我们指定了defaultValue这个属性后,其中required=false是可以省略不写的!!
使用POJO封装哀求参数

先界说一个实体类
  1. @Data
  2. public class Person {
  3.     private String username;
  4.     private String password;
  5.     private String cellphone;
  6.     private boolean agreement;
  7. }
复制代码
  1. @RequestMapping("/handle03")
  2. public String handle03(Person person) {
  3.     System.out.println("handle03()方法执行了!");
  4.     System.out.println(person);
  5.     return "ok";
  6. }
复制代码
如果我们目标方法上的参数是一个POJO时,SpringMVC会自动把哀求参数与POJO属性进行匹配
匹配的原理:利用反射对处置处罚方法上的pojo对象属性进行赋值
注意:要包管可以封装上的话必要哀求参数的名称与pojo对象的属性名可以匹配上!!
如果哀求参数中没有带某个对应属性的参数,则pojo中对应属性的值会封装为默认值。这个默认值如果我们本身要控制的话可以在pojo属性声明上直接给一个初始值就好了!
@RequestHeader获取哀求头

如下所示:
  1. @RequestMapping("/handle04")
  2. public String handle04(@RequestHeader(value = "host",required = false,defaultValue = "localhost") String host,
  3.                        @RequestHeader("user-agent") String userAgent) {
  4.     System.out.println("handle04()方法执行了!");
  5.     System.out.println("userAgent="+userAgent);
  6.     System.out.println("host="+host);
  7.     return "ok";
  8. }
复制代码
获取哀求头的方式与@RequestParam来获取哀求参数的方式是类似的只是这个针对的是哀求头的信息。
@CookieValue获取Cookie

如下所示:
  1. @RequestMapping("/handle05")
  2. public String handle05(@CookieValue("haha") String haha) {
  3.     System.out.println("handle05()方法执行了!");
  4.     System.out.println("haha="+haha);
  5.     return "ok";
  6. }
复制代码
注意:Cookie在前后端分离的项目中是使用不了了的!!
POJO级联封装复杂对象

如下所示:
我们有一个复杂的POJO类Person
  1. @Data
  2. public class Person {
  3.     private String username;
  4.     private String password;
  5.     private String cellphone;
  6.     private boolean agreement;
  7.     private Address address;
  8.     private String sex;
  9.     private String[] hobby;
  10.     private String grade;
  11. }
  12. @Data
  13. class Address {
  14.     private String province;
  15.     private String city;
  16.     private String area;
  17. }
复制代码
在处置处罚器方法参数中使用这个类的对象来进行吸收,会封装为这个POJO的对象
  1. @RequestMapping("/handle06")
  2. public String handle06(Person person) {
  3.     System.out.println("handle06()方法执行了!");
  4.     System.out.println(person);
  5.     return "ok";
  6. }
复制代码
@RequestBody封装json对象

前面我们获取哀求数据的时间哀求的数据都是按key=value这种格式来的
@RequestBody可以取出哀求体的json数据自动转为对象(这里做了一个反序列化)
注意:
         1、json中的数据在哀求体中,所以不可以使用get哀求
         2、在json中不像在表单中,对于boolean值要使用"true"/"false",而不是“on”/"off"
文件文件

SpringMVC中专门使用MultipartFile专门用来封装文件上传的文件项
要对应的取哀求中的哪个文件一般配合@RequestParam来指定
  1. @RequestMapping("/handle08")
  2. public String handle08(Person person,
  3.                        @RequestParam(value = "headerImg",required = false) MultipartFile headerImgFile,
  4.                        @RequestParam(value = "lifeImg",required = false) MultipartFile[] lifeImageFiles) throws IOException {
  5.     System.out.println("handle08()方法执行了!");
  6.     // 创建目标目录
  7.     File targetDir = new File("E:\\Base\\ssm\\ssm-parent\\img");
  8.     if (!targetDir.exists()) {
  9.         targetDir.mkdirs(); // 如果目录不存在,则创建目录
  10.     }
  11.     if (headerImgFile != null) {
  12.         // 获取原始文件名
  13.         String originalFilename = headerImgFile.getOriginalFilename();
  14.         // 获取文件大小
  15.         long size = headerImgFile.getSize();
  16.         // 获取文件流
  17.         InputStream inputStream = headerImgFile.getInputStream();
  18.         System.out.println("originalFilename=" + originalFilename + ",size=" + size);
  19.         // 文件保存
  20.         headerImgFile.transferTo(new File(targetDir, originalFilename));
  21.     }
  22.     if (lifeImageFiles.length > 0) {
  23.         for (MultipartFile lifeImageFile : lifeImageFiles) {
  24.             String originalFilename = lifeImageFile.getOriginalFilename();
  25.             long size = lifeImageFile.getSize();
  26.             InputStream inputStream = lifeImageFile.getInputStream();
  27.             System.out.println("originalFilename=" + originalFilename + ",size=" + size);
  28.             lifeImageFile.transferTo(new File(targetDir, originalFilename));
  29.         }
  30.     }
  31.     System.out.println("=========文件保存成功========");
  32.     System.out.println(person);
  33.     return "ok";
  34. }
复制代码
SpringMVC上传文件是有默认的巨细限制的,如是我们要改这个限制则必要在设置文件中修改
  1. # 单个文件大小限制,默认是1MB,以下配置单件大小限制100MB
  2. spring.servlet.multipart.max-file-size=100MB
  3. # 所以文件大小限制,默认是10MB,以下配置为所有文件大小限制1GB
  4. spring.servlet.multipart.max-request-size=1GB
复制代码

HttpEntity封装哀求原始数据

HttpEntity作为哀求处置处罚方法中的参数类型,它有一个泛型,其中泛型是什么就是哀求体中是什么 。
HttpEntity可以一次性把整个原始哀求拿过来
对于哀求体中的json也可以自动反序列化为指定的对象,比如我们哀求体中是一个josn想让它自动转为Person对象则可以使用HttpEntity<erson>
如下所示:
  1. @RequestMapping("/handle09")
  2. public String handle09(HttpEntity<Person> entity) {
  3.     System.out.println("handle09()方法执行了!");
  4.     // 拿到所有的请求头
  5.     Ht
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

汕尾海湾

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表