JavaEE|SpringMVC
Spring Web MVCSpring Web MVC 是基于 Servlet API 构建的原始 Web 框架从一开始就包含在 Spring 框,SpringWeb MVC 是一个 Web 框架.下面咱们简称之为: Spring MVCMVC 定义MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构设计模式它把软件系统分 为模型、视图和控制器三个基本部分.View(视图)指在应用程序中专门用来与浏览器进行交互展示数据的资源.Model(模型)是应用程序的主体部分用来处理程序中数据逻辑的部分.Controller控制器可以理解为一个分发器用来决定对于视图发来的请求需要用哪一个模型 来处理以及处理完后需要跳回到哪一个视图。即用来连接视图和模型了解Spring MVCSpring MVC 是 Spring 框架中的 Web 模块是一个基于 MVC 设计模式的轻量级 Web 框架。简化理解它主要做三件事核心思想MVC把代码拆分成三层Controller控制器接收请求协调业务。Model模型处理业务逻辑封装数据。View视图展示数据如网页、JSON。核心机制通过一个叫 DispatcherServlet前端控制器 的核心组件统一接收所有请求然后自动分发路由给对应的 Controller 去处理。核心作用解耦让代码各司其职、简化开发通过注解即可轻松写接口主要用于构建 Web 应用和 RESTful API。关于Spring Boot项目的补充我们创建的Spring Boot项目时勾选的Spring Web选项就是运用到了Spring Boot是实现SpringMVC的其中一种方式。Spring Boot 可以添加很多依赖借助这些依赖实现不同的功能。Spring Boot 通过添加SpringWeb MVC框架来实现web功能.学习Spring MVC学习Spring MVC就是学习如何通过浏览器与用户程序进行交互可以通过以下三个方面来学习建立连接将用户浏览器和Java程序连接起来也就是访问一个地址能够调用到我们的Spring程序请求用户请求的时候会带一些参数在程序中要想办法获取到这些参数所以请求这块主要是获取参数的功能响应执行业务逻辑之后要把程序执行的结果返回给用户也就是响应项目准备关于项目的创建上一篇已经讲解如何进行项目创建不清楚的可以去看下上一篇blog建立连接在 Spring MVC 中使用 RequestMapping 来实现 URL 路由映射创建一个UserController类实现用户通过浏览器和程序的交互具体实现代码如下package com.chen.spring.demo; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RequestMapping(/user) RestController public class UserController { RequestMapping(/m1) public String m1(){ return hello world; } }接下来访问: http://127.0.0.1:8080/m1, 就可以看到程序返回的数据了RequestMappingRequestMapping 注解介绍RequestMapping是Spring Web MVC应用程序中最常被用到的注解之一它是用来注册接口的 路由映射的路由映射: 当用户访问一个 URL 时, 将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射.RequestMapping 使用RequestMapping 既可修饰类也可以修饰方法 当修饰类和方法时访问的地址是类路径 方 法路径.RequestMapping标识一个类设置映射请求的请求路径的初始信息RequestMapping标识一个方法设置映射请求请求路径的具体信息注意: RequestMapping 的URL 路径最前面加不加 / (斜杠)都可以, Spring程序启动时, 会进行判断,如果前面没有加 / , Spring会拼接上一个 /请求访问不同的路径,就是发送不同的请求. 在发送请求时可能会带一些参数, 所以学习Spring的请求, 主要是学习如何传递参数到后端以及后端如何接收传递参数, 咱们主要是使用浏览器和Apifox来模拟传递单个参数接收单个参数, 在 Spring MVC 中直接用方法中的参数就可以比如以下代码RequestMapping(/request) RestController public class RequestController { RequestMapping(/r1) public String r1(String keyword) { return 接收参数 keyword; } }状态码显示200表示返回请求成功注意事项使用基本类型来接收参数时, 参数必须传(除boolean类型), 否则会报500错误类型不匹配时, 会报400错误对于包装类型如果不传对应参数Spring 接收到的数据则为null所以企业开发中对于参数可能为空的数据建议使用包装类型传递多个参数如何接收多个参数呢?和接收单个参数一样, 直接使用方法的参数接收即可. 使用多个形参.RequestMapping(/r2) public String r2(String userName, String password){ return 接收参数:userNameuserName, passwordpassword; }当有多个参数时前后端进行参数匹配时是以参数的名称进行匹配的因此参数的位置是不影响后端获取参数的结果.传递对象如果参数比较多时方法声明就需要有很多形参. 并且后续每次新增一个参数, 也需要修改方法声明. 我们不妨把这些参数封装为一个对象.public class UserInfo { private String name; private int gender; private int age; public UserInfo(){ } public UserInfo(String name,int gender,int age){ this.namename; this.gendergender; this.ageage; } public String getName() { return name; } public void setName(String name) { this.name name; } public int getGender() { return gender; } public void setGender(int gender) { this.gender gender; } public int getAge() { return age; } public void setAge(int age) { this.age age; } Override public String toString() { return UserInfo{ name name \ , gender gender , age age }; } }RequestMapping(r5) public String r5(UserInfo userInfo){ return 接收参数userInfouserInfo.toString(); }Spring 会根据参数名称自动绑定到对象的各个属性上, 如果某个属性未传递, 则赋值为null(基本类型则 赋值为默认初识值, 比如int类型的属性, 会被赋值为0)后端参数重命名后端参数重命名也叫做后端参数映射。某些特殊的情况下前端传递的参数和我们后端接收的可以不一致比如前端传递了一个A给后端而后端是使用B字段来接收的这样就会出现参数接收不到的情况如果出现这种情况我们就可以使用 RequestParam 来重命名前后端的参数值.RequestMapping(/r6) public String r6(RequestParam(value q) String keyword){ return 接收参数keyword keyword; }此时, 如果浏览器使用keyword进行参数传递呢?显然访问结果时null表示无法找到可以得出结论使用 RequestParam 进行参数重命名时, 请求参数只能和 RequestParam 声明的名称一 致, 才能进行参数绑定和赋值.使用 RequestParam 进行参数重命名时, 参数就变成了必传参数.非必传参数设置如果存在一个非必传参数我们可以通过设置 RequestParam 中的 requiredfalse 来避免不传递时报错RequestMapping(/r6) public String r6(RequestParam(value q,required false) String keyword){ return 接收参数keyword keyword; }可以看到添加requiredfalse之后time前面也加了key变成了 value time 注解属性赋值时, 没有指明key的话, 默认为value属性. 如果需要有多个属性进行赋值时, 需要写上key传递数组Spring MVC 可以自动绑定数组参数的赋值RequestMapping(/r7) public String r7(String[] arr){ return 接收参数arr Arrays.toString(arr); }传递集合集合参数和数组类似, 同一个请求参数名有为多个, 且需要使用 RequestParam 绑定参数关系RequestMapping(/r8) public String r8(RequestParam ListInteger list){ return 接收参数listlist; }传递JSON数据JSON是一种数据格式, 有自己的格式和语法, 使用文本表示一个对象或数组的信息, JSON本质是字符串. 主要负责在不同的语言中数据传递和交换JSON与Javascript的关系二者没有关系, 只是语法相似, js开发者能更快的上手而已, 但是他的语法本身比较简单, 所以也很好学JSON语法JSON 是一个字符串其格式非常类似于 JavaScript 对象字面量的格式数据在键值对(Key/Value) 中数据由逗号 , 分隔对象用 {} 表示数组用 [] 表示值可以为对象, 也可以为数组, 数组中可以包含多个对象JSON的两种结构对象: 大括号 {} 保存的对象是一个无序的 键值对 集合. 一个对象以左括号 { 开始 右括号 } 结束。每个键后跟一个冒号 : 键值对使用逗号 , 分隔数组: 中括号 [] 保存的数组是值value的有序集合. 一个数组以左中括号 [ 开始 右中括 号 ] 结束值之间使用逗号 , 分隔。JSON字符串和Java对象互转Spring MVC框架也集成了JSON的转换工具用来来完成JSON字符串和Java对象的互转public class Person { private String Name; private int Id; private String Password; public String getName() { return Name; } public void setName(String name) { Name name; } public int getId() { return Id; } public void setId(int Id) { this.Id Id; } public String getPassword() { return Password; } public void setPassword(String password) { Password password; } }public class Json { private static ObjectMapper objectMapper new ObjectMapper(); public static void main(String[] args) throws JsonProcessingException { Person person new Person(); person.setId(5); person.setName(zhangsan); person.setPassword(123456); //对象转为JSON字符串 String jsonStr objectMapper.writeValueAsString(person); System.out.println(JSON字符串为:jsonStr); //JSON字符串转为对象 Person p objectMapper.readValue(jsonStr,Person.class); System.out.println(转换的对象 id:p.getId(),name:p.getName(),password:p.getPassword()); } }使用ObjectMapper 对象提供的两个方法, 可以完成对象和JSON字符串的互转writeValueAsString把对象转为JSON字符串readValue把字符串转为对象JSON优点简单易用语法简单读写快跨平台多语言通用互通好轻量级体积小传输快易扩展结构灵活支持嵌套安全性纯文本无可执行代码传递JSON对象接收JSON对象, 需要使用 RequestBody 注解RequestBodyRequestBody: 请求正文意思是这个注解作用在请求正文的数据绑定请求参数必须在写在请求正 文中后端实现RequestMapping(/r9) public String r9(RequestBody UserInfo userInfo){ return userInfo.toString(); }通过观察响应报头返回的响应格式也为json格式当去除掉 RequestBody后端未能成功给Person对象赋值PathVariablePathVariable用来获取URL中参数path variable: 路径变量。和字面表达的意思一样, 这个注解主要作用在请求URL路径上的数据绑定以获取一篇文章编号为例当我们阅览文章时会发现每一篇文章都有一段对应的编号我们通过代码来实现对编号的获取这里的文章编号是我们自己模拟的RequestMapping(/article/{articleId}) public String r10(PathVariable Integer articleId){ return 获取文章ID:articleId; }注意RequestMapping(/article/{TYPE}/{articleId}) public String r11(PathVariable Integer articleId,PathVariable(TYPE) String type){ return 获取文章ID:articleId, type:type; }如果方法参数名称和需要绑定的URL中的变量名称一致时, 可以简写, 不用给PathVariable的属性赋值, 如上述例子中的article变量如果方法参数名称和需要绑定的URL中的变量名称不一致时, 需要PathVariable的属性value赋值, 如上述例子中的type变量RequestPartRequestPart用来上传指定名称的文件RequestMapping(/r12) public String r12(RequestPart(file11) MultipartFile file) throws IOException { System.out.println(file.getOriginalFilename()); file.transferTo(new File(D:\\code\\file.getOriginalFilename())); return 文件获取成功; }获取Cookie/SessionCookieHTTP 协议自身是属于 无状态 协议.无状态 的含义指的是: 默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的。此时在服务器这边就需要记录客户端信息这个就是 Session 机制所做的工作SessionSession是服务器为了保存用户信息而创建的一个特殊的对象Session的本质就是一个 哈希表, 存储了一些键值对结构关于登录当用户登陆的时候, 服务器在 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数据sessionId也可通过URL传递不依赖Cookie/Set - Cookie。获取CookieRequestMapping(/r14) public String r14(CookieValue(java) String java){ return 从Cookie中获取Java的值java; }此处是向Cookie传值注意区分传值的区域获取Session获取Session有两种方式一种是通过HttpSession来获取另一种就是通过标SessionAttribute来获取RequestMapping(/getSession1) public String getSession2(HttpSession session){ String userName(String) session.getAttribute(userName); int age(int) session.getAttribute(age); return 登录用户名为userName,ageage; } RequestMapping(/getSession2) public String getSession3(SessionAttribute(userName) String userName){ return 登录用户为userName; }获取Session要提前设置这里通过预先设置的setSession可以直接获取到RequestMapping(/setSession) public String setSesssion(HttpServletRequest request){ HttpSession sessionrequest.getSession(); session.setAttribute(userName,zhangsan); session.setAttribute(age,17); return 设置session成功; }获取HeaderHeader中具有以下几个参数以获取Use-Agent为例RequestMapping(/getHeader2) public String getHeader2(RequestHeader(User-Agent) String userAgent){ return 从header中获取userAgentuserAgent; }通过观察结果正确响应返回静态页面要想返回静态页面得先设置一个静态页面为index.html将其放在static目录下RequestMapping(/resp) RestController public class RespController { /** * 返回页面 * * return */ RequestMapping(/r1) public String returnPage() { return /aa/index.html; } }页面未正确返回http响应把 /index.html 当做了http响应正文的数据那Spring MVC如何才能识别出来 index.html 是一个静态页面, 并进行返回呢?当将RestController 改为 ControllerRequestMapping(/resp) Controller public class RespController { RequestMapping(/r1) public String returnPage(){ return /aa/index.html; }此时返回结果为页面数据关于RestController与Controller前面使用的 RestController 其实是返回的数据而Controller是定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理可以理解为RestController Controller ResponseBody此处的ResponseBody是定义返回的数据格式为非视图, 返回一个 text/html 信息查看RestController源码所以如果想返回视图的话, 只需要把 ResponseBody 去掉就可以了, 也就是 Controller返回数据ResponseBodyResponseBody 表示返回数据加上 ResponseBody 注解, 该方法就会把 /index.html 当做一个数据返回给前端.ResponseBody RequestMapping(/r1) public String returnPage(){ return /aa/index.html; }ResponseBody 既是类注解, 又是方法注解如果作用在类上, 表示该类的所有方法返回的都是数据如果作用在方法上, 表示该方法返回的是数据如果一个类的方法里, 既有返回数据的又有返回页面的, 就把 ResponseBody 注解添加到对应的方法上即可返回HTML代码片段后端返回数据时, 如果数据中有HTML代码, 也会被浏览器解析通过Fiddler观察响应结果, Content-Type 为 text/html返回JSON后端方法返回结果为对象ResponseBody RequestMapping(/r5) public UserInfo returnJson(){ UserInfo userInfonew UserInfo(zhangs,10,1); return userInfo; }Content-Type的响应格式text/htmlbody 数据格式是 HTMLtext/cssbody 数据格式是 CSSapplication/javascriptbody 数据格式是 JavaScriptapplication/jsonbody 数据格式是 JSON注意如果请求的是js文件, Spring MVC会自动设置Content-Type为 application/javascript如果请求的是css文件, Spring MVC会自动设置Content-Type为 text/css设置状态码Spring MVC会根据我们方法的返回结果自动设置响应状态码, 程序员也可以手动指定状态码ResponseBody RequestMapping(/r6) public UserInfo setStatus(HttpServletResponse resp){ resp.setStatus(401); UserInfo userInfonew UserInfo(zhangs,10,1); return userInfo; }设置HeaderHttp响应报头也会向客户端传递一些附加信息, 比如服务程序的名称,请求的资源已移动到新地址等, 如: Content-Type, Local等ResponseBody RequestMapping(/r7) public String setHeader(HttpServletResponse resp){ resp.setHeader(myHeader,myHeader); return 设置header成功; }应用分层应用分层 是一种软件开发设计思想, 它将应用程序分成N个层次, 这N个层次分别负责各自的职责三层架构MVC 主要把整体的系统分成了 Model模型 View视图和Controller 控制器三个层次但随着前后端的分离又将后端进行整体架构的分层。通常将整体架构分为表现层、业务逻辑层和数据层这种分层方式也称之为三层架构表现层就是展示数据结果和接受用户指令的是最靠近用户的一层业务逻辑层负责处理业务逻辑, 里面有复杂业务的具体实现数据层负责存储和管理与应用程序相关的数据这三个部分, 在Spring的实现中, 均有体现:Controller控制层。接收前端发送的请求对请求进行处理并响应数据Service业务逻辑层。处理具体的业务逻辑Dao数据访问层也称为持久层。负责数据访问操作包括数据的增、删、改、查0总结1.学习Spring MVC, 其实就是学习各种Web开发需要用的到注解注解含义RequestMapping路由映射RequestParam后端参数重命名RequestBody接收JSON类型的参数PathVariable接收路径参数RequestPart上传文件ResponseBody返回数据CookieValue从Cookie中获取值SessionAttribute从Session中获取值RequestHeader从Header中获取值Controller定义一个控制器, Spring 框架启动时加载, 把这个对象交给Spring管理. 默认返回 视图RestControllerResponseBody Controller 返回数据2.关于Cookie和Session会话机制Cookie(客户端) 与 Session(服务端) 通过 SessionId 关联。Spring MVC 用法直接在方法参数中注入HttpServletRequest/Response。核心操作从 Request 获取 Cookie/Session用 Response 设置状态码。