ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

SpringMVC入门

SpringMVC入门

目录

  • 1. MVC
  • 2. SpringMVC
    • 2.1 @RequestMapping
    • 2.2 请求
    • 2.3 请求传参介绍
    • 2.4 接收参数
      • 2.4.1 接收单个参数
      • 2.4.2 接收多个参数
      • 2.4.3 接收对象
      • 2.4.4 后端参数重命名(参数映射)
      • 2.4.4 接收数组
      • 2.4.5 接收集合
      • 2.4.6 接收JSON
    • 2.5 @PathVariable获取URL参数
    • 2.6 @RequestPart上传文件
    • 2.7 获取Cookie/Session
    • 2.8 获取Header
  • 3. 响应
    • 3.1 返回数据
    • 3.2 返回Json
    • 3.3 设置状态码
    • 3.4 设置Content-Type
    • 3.5 设置其他Header
  • 4. MVC 和三层架构
  • 5. 总结(常见注解)

1. MVC

MVC是 Model View Controller 的缩写,它是软件工程中的一种软件架构设计模式,它把软件系统分为模型、视图和控制器三个基本部分
View(视图) 指在应用程序中专门用来与浏览器进行交互,展示数据的资源
Model(模型) 是应用程序的主体部分,用来处理程序中数据逻辑的部分.
Controller(控制器)可以理解为一个分发器,用来决定对于视图发来的请求,需要用哪一个模型来处理,以及处理完后需要跳回到哪一个视图。即用来连接视图和模型

MVC 是一种架构设计模式, 也是一种思想, 而 Spring MVC 是对 MVC 思想的具体实现.
总结来说,Spring MVC是一个实现了 MVC 模式的 Web 框架

2. SpringMVC

学习Spring MVC, 重点就是学习如何通过浏览器和用户程序进行交互

  1. 建立连接:将用户(浏览器)和 Java 程序连接起来,也就是访问一个地址能够调用到我们的Spring 程序
  2. 请求: 用户请求的时候会带一些参数,在程序中要想办法获取到参数, 所以请求这块主要是 获取参数的功能
  3. 响应: 执行了业务逻辑之后,要把程序执行的结果返回给用户, 也就是响应

2.1 @RequestMapping

在 Spring MVC 中使用 @RequestMapping 来实现 URL 路由映射
路由映射: 当用户访问一个 URL 时, 将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射

是 Spring Web MVC 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的.
@RequestMapping 既可修饰类,也可以修饰方法 ,当修饰类和方法时,访问的地址是类路径 + 方法路径

@RequestMapping标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息
@RequestMapping 的URL路径也可以是多层路径, 最终访问时, 依然是 类路径 + 方法路径

@RestController@RequestMapping("/user")publicclassUserController{@RequestMapping("/hi")publicStringsayHi(){return"hello";}}

@RequestMapping 既支持Get请求, 又支持Post请求. 同理, 也支持其他的请求方式
用Post方式举例, @PostMapping 和通过 @RequestMapping(method = RequestMethod.POST)都可以指定请求方法类型

2.2 请求

访问不同的路径, 就是发送不同的请求. 在发送请求时, 可能会带一些参数, 所以学习Spring的请求, 主要是学习如何传递参数到后端以及后端如何接收

2.3 请求传参介绍

可以使用postman来构造请求, 以下是postman部分请求传参介绍
普通传参, 也就是通过查询字符串来传参, 查询字符串就是请求的参数
form-data(完整表示为: multipart/form-data), 对应 Content-Type: multipart/form-data
x-www-form-urlencoded: 对应 Content-Type: application/x-www-from-urlencoded
raw: 可以上传任意格式的文本,可以上传text、json、xml、html等

2.4 接收参数

后端开发人员无需过度关注如何传递参数, 了解即可, 实际开发中以Postman测试为主

2.4.1 接收单个参数

接收单个参数, 在 Spring MVC 中直接用方法中的参数就可以

@RestController@RequestMapping("/param")publicclassParamController{@RequestMapping("/m1")publicStringm1(Stringstr){return"接收到参数:"+str;}}

使用基本类型来接收参数时, 参数必须传(除boolean类型), 否则会报500错误
类型不匹配时, 会报400错误
被声明为基本类型而不能转换为空值. 考虑将其声明为对应基本类型的包装类型. 对于包装类型, 如果不传对应参数,Spring 接收到的数据则为null所以企业开发中,对于参数可能为空的数据,建议使用包装类型

2.4.2 接收多个参数

和接收单个参数一样, 直接使用方法的参数接收即可. 使用多个形参

@RequestMapping("/m2")publicStringm2(Stringstr1,Stringstr2){return"接收到参数1:"+str1+", 接收到参数2:"+str2;}

当有多个参数时,前后端进行参数匹配时,是以参数的名称进行匹配的,因此参数的位置是不影响后端获取参数的结果

2.4.3 接收对象

如果参数比较多时, 方法声明就需要有很多形参. 并且后续每次新增一个参数, 也需要修改方法声明.我们不妨把这些参数封装为一个对象

@RequestMapping("/m3")publicObjectm3(Personp){returnp.toString();}

Spring 会根据参数名称自动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为null(基本类型则赋值为默认初识值, 比如int类型的属性, 会被赋值为0)

2.4.4 后端参数重命名(参数映射)

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

@RequestMapping("/m4")publicObjectm4(@RequestParam("time")StringcreateTime){return"接收到参数:"+createTime;}
  1. 使用 @RequestParam 进行参数重命名时, 请求参数只能和 @RequestParam声明的名称一致, 才能进行参数绑定和赋值
  2. 使用 @RequestParam 进行参数重命名时, 参数就变成了必传参数

如果我们的实际业务前端的参数是一个非必传的参数, 针对上述问题, 如何解决呢?

可以看到 required 的默认值为true, 表示含义就是: 该注解修饰的参数默认为必传

@RequestMapping("/m4")publicObjectm4(@RequestParam(value="time",required=false)StringcreateTime){return"接收到参数:"+createTime;}

我们将required设置为false, 就可以将其设置为非必传参数

2.4.4 接收数组

Spring MVC 可以自动绑定数组参数的赋值

@RequestMapping("/m5")publicObjectm5(String[]arrayParam){returnArrays.toString(arrayParam);}

请求参数名与形参数组名称相同且请求参数为多个, 后端定义数组类型形参即可接收参数,推荐用postman发送数组更方便

2.4.5 接收集合

集合参数:和数组类似, 同一个请求参数名有为多个, 且需要使用@RequestParam 绑定参数关系, 请求方式和数组类似

默认情况下,请求中参数名相同的多个值,是封装到数组. 如果要封装到集合,要使用@RequestParam 绑定参数关系

@RequestMapping("/m6")publicStringm6(@RequestParamList<String>listParam){return"size:"+listParam.size()+",listParam:"+listParam;}

2.4.6 接收JSON

接收JSON对象, 需要使用@RequestBody注解

@RequestMapping(value="/m7")publicObjectm7(@RequestBodyPersonperson){returnperson.toString();}

2.5 @PathVariable获取URL参数

path variable: 路径变量
默认传递参数写在URL上,SpringMVC就可以获取到

@RequestMapping("/m8/{id}/{name}")publicStringmethod8(@PathVariableIntegerid,@PathVariable("name")StringuserName){return"解析参数id:"+id+",name:"+userName;}

如果方法参数名称和需要绑定的URL中的变量名称一致时, 可以简写, 不用给@PathVariable的属性赋值, 如上述例子中的id变量: @PathVariable Integer id
如果方法参数名称和需要绑定的URL中的变量名称不一致时, 需要@PathVariable的属性value赋值,如上述例子中的userName变量:
@PathVariable(“name”) String username

2.6 @RequestPart上传文件

@RequestMapping("/m9")publicStringgetfile(@RequestPart("file")MultipartFilefile)throwsIOException{StringfileName=file.getOriginalFilename();file.transferTo(newFile("D:/temp/"+file.getOriginalFilename()));return"接收到文件名称为: "+fileName;}

2.7 获取Cookie/Session

回顾Session, 之前文章写过Cookie和Session, 此处回顾一下
HTTP 协议自身是属于 “无状态” 协议, 但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的

Session的本质就是一个 “哈希表”, 存储了一些键值对结构. Key 就是SessionID, Value 就是用户信息(用户信息可以根据需求灵活设计)

SessionId 是由服务器生成的一个 “唯一性字符串”, 从 Session 机制的角度来看, 这个唯一性字符串称为 “SessionId”. 但是站在整个登录流程中看待, 也可以把这个唯一性字符串称为 “token”.

  1. 当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId返回给客户端. (通过HTTP 响应中的 Set-Cookie 字段返回)
  2. 客户端后续再给服务器发送请求的时候, 需要在请求中带上sessionId. (通过 HTTP 请求中的Cookie 字段带上).
  3. 服务器收到请求之后, 根据请求中的 sessionId在 Session 信息中获取到对应的用户信息, 再进行后续操作.找不到则重新创建Session, 并把SessionID返回

Cookie 和 Session 的区别
• Cookie 是客户端保存用户信息的一种机制. Session 是服务器端保存用户信息的一种机制.
• Cookie 和 Session之间主要是通过 SessionId 关联起来的, SessionId 是 Cookie 和 Session 之间的
桥梁
• Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.
◦ 完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是SessionId
◦ Session 中的sessionId也不需要非得通过 Cookie/Set-Cookie 传递, 比如通过URL传递.

获取Cookie
传统获取Cookie

@RequestMapping("/m10")publicStringmethod10(HttpServletRequestrequest,HttpServletResponseresponse){// 获取所有 cookie 信息Cookie[]cookies=request.getCookies();//打印Cookie信息StringBuilderbuilder=newStringBuilder();if(cookies!=null){for(Cookieck:cookies){builder.append(ck.getName()+":"+ck.getValue());}}return"Cookie信息:"+builder;}

HttpServletRequest , HttpServletResponse 是Servlet提供的两个类, 是Spring MVC方法的内置对象. 需要时直接在方法中添加声明即可
HttpServletRequest对象代表客户端的请求, 当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象提供的方法,可以获得客户端请求的所有信息
HttpServletResponse对象代表服务器的响应. HTTP响应的信息都在这个对象中, 比如向客户端发送的数据, 响应头, 状态码等. 通过这个对象提供的方法, 可以获得服务器响应的所有内容

Spring MVC在这两个对象的基础上进行了封装, 给我们提供更加简单的使用方法@CookieValue

@RequestMapping("/getCookie")publicStringcookie(@CookieValue("name")Stringname){return"name:"+name;}

存储Session
Session是服务器端的机制, 我们需要先存储, 才能再获取
Session 也是基于HttpServletRequest 来存储和获取的

这个代码中看不到 SessionId 这样的概念的. getSession 操作内部提取到请求中的Cookie 里的SessionId, 然后根据SessionId获取到对应的Session 对象, Session 对象用HttpSession来描述

@RequestMapping("/setSess")publicStringsetsess(HttpServletRequestrequest){// 获取Session对象HttpSessionsession=request.getSession();if(session!=null){session.setAttribute("username","java");}return"session 存储成功";}

HttpSession getSession(boolean create) : 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null
void setAttribute(String name, Object value): 使用指定的名称绑定一个对象到该 session 会话

获取Session
读取 Session 可以使用 HttpServletRequest

@RequestMapping("/getSess")publicStringsess(HttpServletRequestrequest){// 如果 session 不存在, 不会自动创建HttpSessionsession=request.getSession(false);StringuserName=null;if(session!=null&&session.getAttribute("username")!=null){userName=session.getAttribute("username").toString();}returnuserName;}

Object getAttribute(String name): 返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null.

同样, Session获取也有简单方法: @SessionAttribute

@RequestMapping("/getSess2")publicStringsess2(@SessionAttribute(value="username",required=false)Stringusername){return"username:"+username;}

或者用内置的HttpSession

@RequestMapping("/getSess3")publicStringsess3(HttpSessionsession){Stringusername=(String)session.getAttribute("username");return"username:"+username;}

HttpSession session = request.getSession();
Session 不存在的话, 会自动进行创建

2.8 获取Header

获取Header也是从 HttpServletRequest 中获取

@RequestMapping("/param10")publicStringparam10(HttpServletRequestrequest,HttpServletResponseresponse){StringuserAgent=request.getHeader("User-Agent");returnuserAgent;}

简洁获取 Header: @RequestHeader

@RequestMapping("/header")publicStringheader(@RequestHeader("User-Agent")StringuserAgent){return"userAgent:"+userAgent;}

3. 响应

Http响应结果可以是数据, 也可以是静态页面,也可以针对响应设置状态码, Header信息等

3.1 返回数据

@RestController 和 @Controller 有着什么样的关联和区别呢?
随着互联网的发展, 目前项目开发流行"前后端分离"模式, Java主要是用来做后端项目的开发, 所以也就不再处理前端相关的内容了
MVC的概念也逐渐发生了变化, View不再返回视图, 而是返回显示视图时需要的数据
@RestController = @Controller + @ResponseBody
@Controller : 定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理
@ResponseBody : 定义返回的数据格式为非视图, 返回一个 text/html 信息
如果想返回视图的话, 只需要把 @ResponseBody 去掉就可以了, 也就是 @Controller

@ResponseBody 表示返回数据, 既是类注解, 又是方法注解
如果作用在类上, 表示该类的所有方法, 返回的都是数据, 如果作用在方法上, 表示该方法返回的是数据.

3.2 返回Json

后端方法返回结果为对象, 浏览器响应

@RequestMapping("/returnJson")@ResponseBodypublicHashMap<String,String>returnJson(){HashMap<String,String>map=newHashMap<>();map.put("Java","Java Value");map.put("MySQL","MySQL Value");map.put("Redis","Redis Value");returnmap;}

Spring发现@ResponseBody,就会进行序列化

3.3 设置状态码

Spring MVC会根据我们方法的返回结果自动设置响应状态码, 程序员也可以手动指定状态码通过Spring MVC的内置对象HttpServletResponse 提供的方法来进行设置

@RequestMapping(value="/setStatus")@ResponseBodypublicStringsetStatus(HttpServletResponseresponse){response.setStatus(401);return"设置状态码成功";}

3.4 设置Content-Type

我们通过设置@RequestMapping的 produces属性的值, 设置响应的报头Content-Type

@RequestMapping(value="/returnJson2",produces="application/json")@ResponseBodypublicStringreturnJson2(){return"{\"success\":true}";}

3.5 设置其他Header

设置其他Header的话, 需要使用Spring MVC的内置对象HttpServletResponse 提供的方法来进行设置

@RequestMapping(value="/setHeader")@ResponseBodypublicStringsetHeader(HttpServletResponseresponse){response.setHeader("MyHeader","MyHeaderValue");return"设置Header成功";}

4. MVC 和三层架构

对于Java后端开发者, 把整体架构分为表现层、业务逻辑层和数据层. 这种分层方式也称之为"三层架构"
请求处理、响应数据:负责,接收页面的请求,给页面响应数据
逻辑处理:负责业务逻辑处理的代码
数据访问:负责业务数据的维护操作,包括增、删、改、查等操作.

在Spring中的体现就是

  1. Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据
  2. Service:业务逻辑层。处理具体的业务逻辑
  3. Dao:数据访问层,也称为持久层。负责数据访问操作,包括数据的增、删、改、查.

MVC 和三层架构的区别和联系:
关于二者的关系, 一直存在不同的观点. 有人认为三层架构是MVC模式的一种实现, 也有人认为MVC是三层架构的替代方案, 等等
二者其实是从不同角度对软件工程进行了抽象.
MVC模式强调数据和视图分离, 将数据展示和数据处理分开, 通过控制器对两者进行组合.
三层架构强调不同维度数据处理的高内聚和低耦合, 将交互界面, 业务处理和数据库操作的逻辑分开.
角度不同也就谈不上互相替代了,在日常的开发中可以经常看到两种共存的情况,比如我们设计模型层的时候往往也会拆分出业务逻辑层(Service层)和数据访问层(Dao层)

5. 总结(常见注解)

@RequestMapping: 路由映射
@RequestParam: 后端参数重命名
@RequestBody: 接收JSON类型的参数
@PathVariable: 接收路径参数
@RequestPart: 上传文件
@ResponseBody: 返回数据
@CookieValue: 从Cookie中获取值
@SessionAttribute: 从Session中获取值
@RequestHeader: 从Header中获取值
@Controller: 定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理. 默认返回视图.
@RestController: @ResponseBody + @Controller 返回数据

返回列表