
目录1. MVC2. SpringMVC2.1 RequestMapping2.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 接收JSON2.5 PathVariable获取URL参数2.6 RequestPart上传文件2.7 获取Cookie/Session2.8 获取Header3. 响应3.1 返回数据3.2 返回Json3.3 设置状态码3.4 设置Content-Type3.5 设置其他Header4. MVC 和三层架构5. 总结(常见注解)1. MVCMVC是 Model View Controller 的缩写它是软件工程中的一种软件架构设计模式它把软件系统分为模型、视图和控制器三个基本部分View(视图) 指在应用程序中专门用来与浏览器进行交互展示数据的资源Model(模型) 是应用程序的主体部分用来处理程序中数据逻辑的部分.Controller控制器可以理解为一个分发器用来决定对于视图发来的请求需要用哪一个模型来处理以及处理完后需要跳回到哪一个视图。即用来连接视图和模型MVC 是一种架构设计模式, 也是一种思想, 而 Spring MVC 是对 MVC 思想的具体实现.总结来说Spring MVC是一个实现了 MVC 模式的 Web 框架2. SpringMVC学习Spring MVC, 重点就是学习如何通过浏览器和用户程序进行交互建立连接将用户浏览器和 Java 程序连接起来也就是访问一个地址能够调用到我们的Spring 程序请求: 用户请求的时候会带一些参数在程序中要想办法获取到参数, 所以请求这块主要是 获取参数的功能响应: 执行了业务逻辑之后要把程序执行的结果返回给用户, 也就是响应2.1 RequestMapping在 Spring MVC 中使用 RequestMapping 来实现 URL 路由映射路由映射: 当用户访问一个 URL 时, 将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射是 Spring Web MVC 应用程序中最常被用到的注解之一它是用来注册接口的路由映射的.RequestMapping 既可修饰类也可以修饰方法 当修饰类和方法时访问的地址是类路径 方法路径RequestMapping标识一个类设置映射请求的请求路径的初始信息RequestMapping标识一个方法设置映射请求请求路径的具体信息RequestMapping 的URL路径也可以是多层路径, 最终访问时, 依然是 类路径 方法路径RestControllerRequestMapping(/user)publicclassUserController{RequestMapping(/hi)publicStringsayHi(){returnhello;}}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-datax-www-form-urlencoded: 对应 Content-Type: application/x-www-from-urlencodedraw: 可以上传任意格式的文本可以上传text、json、xml、html等2.4 接收参数后端开发人员无需过度关注如何传递参数, 了解即可, 实际开发中以Postman测试为主2.4.1 接收单个参数接收单个参数, 在 Spring MVC 中直接用方法中的参数就可以RestControllerRequestMapping(/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;}使用 RequestParam 进行参数重命名时, 请求参数只能和 RequestParam声明的名称一致, 才能进行参数绑定和赋值使用 RequestParam 进行参数重命名时, 参数就变成了必传参数如果我们的实际业务前端的参数是一个非必传的参数, 针对上述问题, 如何解决呢?可以看到 required 的默认值为true, 表示含义就是: 该注解修饰的参数默认为必传RequestMapping(/m4)publicObjectm4(RequestParam(valuetime,requiredfalse)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(RequestParamListStringlistParam){returnsize: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 username2.6 RequestPart上传文件RequestMapping(/m9)publicStringgetfile(RequestPart(file)MultipartFilefile)throwsIOException{StringfileNamefile.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”.当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId返回给客户端. (通过HTTP 响应中的 Set-Cookie 字段返回)客户端后续再给服务器发送请求的时候, 需要在请求中带上sessionId. (通过 HTTP 请求中的Cookie 字段带上).服务器收到请求之后, 根据请求中的 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传统获取CookieRequestMapping(/m10)publicStringmethod10(HttpServletRequestrequest,HttpServletResponseresponse){// 获取所有 cookie 信息Cookie[]cookiesrequest.getCookies();//打印Cookie信息StringBuilderbuildernewStringBuilder();if(cookies!null){for(Cookieck:cookies){builder.append(ck.getName():ck.getValue());}}returnCookie信息:builder;}HttpServletRequest , HttpServletResponse 是Servlet提供的两个类, 是Spring MVC方法的内置对象. 需要时直接在方法中添加声明即可HttpServletRequest对象代表客户端的请求, 当客户端通过HTTP协议访问服务器时HTTP请求头中的所有信息都封装在这个对象中通过这个对象提供的方法可以获得客户端请求的所有信息HttpServletResponse对象代表服务器的响应. HTTP响应的信息都在这个对象中, 比如向客户端发送的数据, 响应头, 状态码等. 通过这个对象提供的方法, 可以获得服务器响应的所有内容Spring MVC在这两个对象的基础上进行了封装, 给我们提供更加简单的使用方法CookieValueRequestMapping(/getCookie)publicStringcookie(CookieValue(name)Stringname){returnnamename;}存储SessionSession是服务器端的机制, 我们需要先存储, 才能再获取Session 也是基于HttpServletRequest 来存储和获取的这个代码中看不到 SessionId 这样的概念的. getSession 操作内部提取到请求中的Cookie 里的SessionId, 然后根据SessionId获取到对应的Session 对象, Session 对象用HttpSession来描述RequestMapping(/setSess)publicStringsetsess(HttpServletRequestrequest){// 获取Session对象HttpSessionsessionrequest.getSession();if(session!null){session.setAttribute(username,java);}returnsession 存储成功;}HttpSession getSession(boolean create) : 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 nullvoid setAttribute(String name, Object value): 使用指定的名称绑定一个对象到该 session 会话获取Session读取 Session 可以使用 HttpServletRequestRequestMapping(/getSess)publicStringsess(HttpServletRequestrequest){// 如果 session 不存在, 不会自动创建HttpSessionsessionrequest.getSession(false);StringuserNamenull;if(session!nullsession.getAttribute(username)!null){userNamesession.getAttribute(username).toString();}returnuserName;}Object getAttribute(String name): 返回在该 session 会话中具有指定名称的对象如果没有指定名称的对象则返回 null.同样, Session获取也有简单方法: SessionAttributeRequestMapping(/getSess2)publicStringsess2(SessionAttribute(valueusername,requiredfalse)Stringusername){returnusernameusername;}或者用内置的HttpSessionRequestMapping(/getSess3)publicStringsess3(HttpSessionsession){Stringusername(String)session.getAttribute(username);returnusernameusername;}HttpSession session request.getSession();Session 不存在的话, 会自动进行创建2.8 获取Header获取Header也是从 HttpServletRequest 中获取RequestMapping(/param10)publicStringparam10(HttpServletRequestrequest,HttpServletResponseresponse){StringuserAgentrequest.getHeader(User-Agent);returnuserAgent;}简洁获取 Header: RequestHeaderRequestMapping(/header)publicStringheader(RequestHeader(User-Agent)StringuserAgent){returnuserAgentuserAgent;}3. 响应Http响应结果可以是数据, 也可以是静态页面,也可以针对响应设置状态码, Header信息等3.1 返回数据RestController 和 Controller 有着什么样的关联和区别呢?随着互联网的发展, 目前项目开发流行前后端分离模式, Java主要是用来做后端项目的开发, 所以也就不再处理前端相关的内容了MVC的概念也逐渐发生了变化, View不再返回视图, 而是返回显示视图时需要的数据RestController Controller ResponseBodyController : 定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理ResponseBody : 定义返回的数据格式为非视图, 返回一个 text/html 信息如果想返回视图的话, 只需要把 ResponseBody 去掉就可以了, 也就是 ControllerResponseBody 表示返回数据 既是类注解, 又是方法注解如果作用在类上, 表示该类的所有方法, 返回的都是数据, 如果作用在方法上, 表示该方法返回的是数据.3.2 返回Json后端方法返回结果为对象, 浏览器响应RequestMapping(/returnJson)ResponseBodypublicHashMapString,StringreturnJson(){HashMapString,StringmapnewHashMap();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-TypeRequestMapping(value/returnJson2,producesapplication/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中的体现就是Controller控制层。接收前端发送的请求对请求进行处理并响应数据Service业务逻辑层。处理具体的业务逻辑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 返回数据