SpringMVC
SpringMVC 是一种轻量级的, 基于 MVC 的 web 层应用框架.
通过一套 MVC 注解, 让 POJO 成为处理请求的控制器, 而无须实现任何接口.
采用了松散耦合可插拔组件结构, 比其他 MVC 框架更具扩展性和灵活性.
优点:
1, 天生与 Spring 框架集成, 如:(IoC,AOP)
2, 支持 Restful 风格
3, 支持灵活的 URL 到页面控制器的映射
4, 非常容易与其他视图技术集成, 如: Velocity,FreeMarker 等等
5, 因为模型数据不存放在特定的 API 里, 而是放在一个 Model 里(Map 数据结构实现, 因此很容易被其他框架使用)
6, 非常灵活的数据验证, 格式化和数据绑定机制, 能使用任何对象进行数据绑定,
7, 更加简单, 强大的异常处理
8, 对静态资源的支持
9, 支持灵活的本地化, 主题等解析
常用主要组件
1 DispatcherServlet: 前端控制器
2 Controller: 处理器 / 页面控制器, 做的是 MVC 中的 C 的事情, 但控制逻辑转移到前端控制器了, 用于对请求进行处理
3 HandlerMapping: 请求映射到处理器, 找谁来处理, 如果映射成功返回一个 HandlerExecutionChain 对象 (包含一个 Handler 处理器(页面控制器) 对象, 多个 HandlerInterceptor 拦截器对象)
4 View Resolver : 视图解析器, 找谁来处理返回的页面. 把逻辑视图解析为具体的 View, 进行这种策略模式, 很容易更换其他视图技术; 如 InternalResourceViewResolver 将逻辑视图名映射为 JSP 视图
5 LocalResolver: 本地化, 国际化
6 MultipartResolver: 文件上传解析器
7 HandlerExceptionResolver: 异常处理器
Spring MVC 的配置文件
流程分析
基本步骤:
1 客户端请求提交到 DispatcherServlet
2 由 DispatcherServlet 控制器查询一个或多个 HandlerMapping, 找到处理请求的 Controller
3 DispatcherServlet 将请求提交到 Controller(也称为 Handler)
4 Controller 调用业务逻辑处理后, 返回 ModelAndView
5 DispatcherServlet 查询一个或多个 ViewResoler 视图解析器, 找到 ModelAndView 指定的视图
6 视图负责将结果显示到客户端
标准的 HTTP 请求报头
@RequestMapping
1, 使用 @RequestMapping 注解来映射请求的 URL
@RequestMapping 可以应用的地方
- @Target({
- ElementType.METHOD, ElementType.TYPE
- })
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Mapping
- public @interface RequestMapping {
- ...
- }
请求的方式有
- public enum RequestMethod {
- GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
- }
@RequestMapping 可以为控制器指定可以处理哪些 URL 请求, 将该注解中的 value 属性值映射成 URL, 客户端可以通过该 URL 请求到指定类中的方法.
1)在控制器的类定义或方法定义处都可标注 @RequestMapping
1 标记在类上: 提供初步的请求映射信息. 相对于 Web 应用的根目录
2 标记在方法上: 提供进一步的细分映射信息. 相对于标记在类上的 URL.
2)若类上未标注 @RequestMapping, 则方法处标记的 URL 相对于 Web 应用的根目录
3)作用: DispatcherServlet 截获请求后, 就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法.
@RequestMapping 属性
value: 指定 URL 路径
method: 指定请求方式
params: 指定请求参数
headers: 指定请求头信息
映射请求参数, 请求方式或请求头
1)@RequestMapping 除了可以使用请求 URL 映射请求外, 还可以使用请求方法, 请求参数及请求头来精确映射对应请求
2)@RequestMapping 的 value[重点] ,method[重点] ,params[了解] 及 heads[了解] 分别表示请求 URL, 请求方式, 请求参数及请求头的映射条件, 他们之间是与的关系, 联合使用多个条件可让请求映射更加精确化. 即: 需满足所有映射条件才可匹配到对应方法
3)params 和 headers 支持简单的表达式:
param1: 表示请求必须包含名为 param1 的请求参数
!param1: 表示请求不能包含名为 param1 的请求参数
param1 != value1: 表示请求包含名为 param1 的请求参数, 但其值不能为 value1
{"param1=value1", "param2"}: 请求必须包含名为 param1 和 param2 的两个请求参数, 且 param1 参数的值必须为 value1
Ant 路径风格
Ant 风格资源地址支持 3 种匹配符:[了解]
?: 匹配文件名中的一个字符
*: 匹配文件名中的任意字符
**:** 匹配多层路径
- /user/*/**/createUser??
- 匹配 /user/xxx / 多层 / createUserXX
- REST
- REST 是什么? 因为 REST 的内涵非常丰富, 所以很难用一两句话解释清楚这个问题. 首先, REST 是 Web 自身的架构风格.
- 参考资料: 理解本真的 REST 架构风格
- REST: 即 Representational State Transfer.(资源)表现层状态转化. 是目前最流行的一种互联网软件架构. 它结构清晰, 符合标准, 易于理解, 扩展方便
- 资源 (Resources): 资源是一种看待服务器的方式. 是网络上的一个实体, 可以是一段文本, 一张图片, 可以用一个 URI(统一资源定位符, 独一无二的识别符) 指向它, 获取这个资源, 访问它的 URI 就可以了
- 表现层: 资源的表述 (Representation) 是一段对于资源在某个特定时刻的状态的描述, 即把资源具体呈现出来的形式, 比如, 文本可以用 txt ,JSON 格式表现, 甚至可以采用二进制格式.
- 状态转化 (State Transfer): 状态转移说的是: 在客户端和服务器端之间转移(transfer) 代表资源状态的表述. 通过转移和操作资源的表述, 来间接实现操作资源的目的. 如: 每发出一个请求, 就代表了客户端和服务器的一次交互过程. HTTP 协议, 是一个无状态协议, 即所有的状态都保存在服务器端. 因此, 如果客户端想要操作服务器, 必须通过某种手段, 让服务器端发生 "状态转化". 而这种转化是建立在表现层之上的, 所以就是 "表现层状态转化".
- 统一接口(Uniform Interface)REST 要求, 必须通过统一的接口来对资源执行各种操作. 对于每个资源只能执行一组有限的操作. 例如: HTTP/1.1 协议定义了一个操作资源的统一接口. REST 还要求, 对于资源执行的操作, 其操作语义必须由 HTTP 消息体之前的部分完全表达, 不能将操作语义封装在 HTTP 消息体内部. 这样做是为了提高交互的可见性
- 超文本驱动 (Hypertext Driven) 将 Web 应用看作是一个由很多状态 (应用状态) 组成的有限状态机. 资源之间通过超链接相互关联, 超链接既代表资源之间的关系, 也代表可执行的状态迁移. 即: 客户端应该依赖的是超媒体的状态迁移语义, 而不应该对于是否存在某个 URI 或 URI 的某种特殊构造方式作出假设. 一切都有可能变化, 只有超媒体的状态迁移语义能够长期保持稳定.
- 具体对于 HTTP 来说, 就是 HTTP 协议里面对应的四种常用基本操作: GET 用来获取资源, POST 用来新建资源, PUT 用来更新资源, DELETE 用来删除资源. 应使用由客户端定义的请求方式指定对应的某种操作, 而不应该通过某种特殊构造方式进行指定
- HiddenHttpMethodFilter 过滤器
- 浏览器 form 表单只支持 GET 与 POST 请求, HiddenHttpMethodFilter 可以将 POST 请求转换为标准的 http 方法以达到 REST 风格
- 使用步骤
- 1. 必须将 form 表单中的 method 设置为 POST
- 2. 提交表单时, 必须提交 "_method" 参数, 一般使用隐藏域
- 原因: HiddenHttpMethodFilter 过滤器将 HttpServletRequest 中的 getMethod()方法, 重写啦.
- <!-- 配置处理请求方式 -->
- <filter>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <filter-class>org.springframework.Web.filter.HiddenHttpMethodFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>hiddenHttpMethodFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- 处理请求数据
- Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中, 并根据方法的返回值类型做出相应的后续处理.
- 可以对方法及方法入参标注相应的注解( @PathVariable ,@RequestParam,@RequestHeader 等)
- @PathVariable 请求占位符
- 是 Spring3.0 新增的功能, 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中
- //@PathVariable 注解可以将请求 URL 路径中的请求参数, 传递到处理请求方法的入参中
- // 浏览器的请求为: testPathVariable/1001
- @RequestMapping(value="/testPathVariable/{id}",method=RequestMethod.DELET)
- public String testPathVariable(@PathVariable("id") Integer id) {}
- @RequestParam 请求参数
- 如果请求参数与形参不一致时, 可以使用 @RequestParam 注解实现获取参数值
- 书写位置: 标注在方法的参数中, springMVC 默认会将请求参数注入 (绑定) 到方法形参中(两个参数名一致)
- 一旦使用该注解, 必须为相应参数传参数. 如果未传参, 会报错: 400, 因为 required 默认为 true,
- value: 用于映射请求参数名称
- required: 是否必须. 默认为 true, 表示请求参数中必须包含对应的参数, 若不存在, 将抛出异常
- defaultValue: 默认值, 当没有传递参数时使用该值作为默认值, 不设默认为 null
- @RequestMapping(value="/testRequestParam?username=guigu&age=10")
- public String testRequestParam(
- @RequestParam(value="username") String username,
- @RequestParam(value="age",required=false,defaultValue="0") int age){
- return "success";
- }
- @RequestHeader 请求头
- 获取请求头信息, 请求头包含了若干个属性, 服务器可据此获知客户端的信息, 通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中
- @CookieValue
- 获取指定的 Cookie 信息, 可让处理方法入参绑定某个 Cookie 值
- 使用 POJO 作为参数
- Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值. 支持级联属性.
- @RequestMapping(value = "/emps",method = RequestMethod.PUT)
- public String updateEmp(Employee employee){
- employeeDao.save(employee);
- return "redirect:/emps";
- }
- //Spring MVC 会按请求参数名和 Employee 属性名进行自动匹配, 自动为该对象填充属性值. 支持级联属性
- 配置字符编码过滤器
- <!-- 处理 POST 请求和响应乱码 -->
- <filter>
- <filter-name>characterEncodingFilter</filter-name>
- <filter-class>org.springframework.Web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <filter-mapping>
- <filter-name>characterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- GET 请求乱码
- GET 请求参数是在地址后面的. 我们需要修改 tomcat 的配置文件. 需要在 server.xml 文件修改 Connector 标签, 添加 URIEncoding="utf-8" 属性.
- 使用 Servlet 原生 API
- /**
- * 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型
- * HttpServletRequest
- * HttpServletResponse
- * HttpSession
- * java.security.Principal
- * Locale
- * InputStream
- * OutputStream
- * Reader
- * Writer
- */
- @RequestMapping("/testServletAPI")
- public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException {
- System.out.println("testServletAPI," + request + "," + response);
- out.write("hello springmvc");
- }
处理响应数据
2, 返回值会通过视图解析器解析为实际的物理视图
输出模型数据类型
1) ModelAndView: 作为返回值类型, 响应数据: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据
2) String: 作为返回值类型, 即为视图信息直接找字符串映射 URL 路径, 转发或重定向
3) Map 或 Model: 作为参数, 响应数据: 入参为 Model,ModelMap 或 Map, 处理方法返回时, Map 中的数据会自动添加到模型中.
ModelAndView
控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息, 也包含模型数据信息.
1) 两个重要的成员变量:
private Object view; [视图信息]
private ModelMap model; [模型数据]
2)添加模型数据:
MoelAndView addObject(String attributeName, Object attributeValue) [设置模型数据]
ModelAndView addAllObject(Map<String, ?> modelMap)
4)设置视图:
void setView(View view) [设置视图对象]
void setViewName(String viewName) [设置视图名字]
5)获取模型数据
protected Map<String, Object> getModelInternal() [获取模型数据]
- public ModelMap getModelMap()
- public Map<String, Object> getModel()
- @RequestMapping("/testModelAndView")
- public ModelAndView testModelAndView(){
- String viewName = "success";
- ModelAndView mv = new ModelAndView(viewName);
- mv.addObject("time",new Date().toString()); // 实质上存放到 request 域中
- return mv;
- }
ModelAndView 底层工作原理, 不论控制器返回一个 String,ModelAndView,View 都会转换为 ModelAndView 对象, 将数据放到 request 域中, 再通过转发实现页面跳转
Map Model
Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器.
如果方法的入参为 Map 或 Model 类型, Spring MVC 会将隐含模型的引用传递给这些入参.
在方法体内, 开发者可以通过这个入参对象访问到模型中的所有数据, 也可以向模型中添加新的属性数据
- // 目标方法的返回类型也可以是一个 Map 类型参数(也可以是 Model, 或 ModelMap 类型)
- @RequestMapping("/testMap")
- public String testMap(Map<String, Object> map) { //[重点]
- System.out.println(map.getClass().getName());
- //org.springframework.validation.support.BindingAwareModelMap
- map.put("names", Arrays.asList("Tom", "Jerry", "Kite"));
- return "success";
- }
注意问题: Map 集合的泛型, key 为 String,Value 为 Object, 而不是 String
由源码可知: 不论用那个类型作为数据模型, 其内部都会转化为 BindingAwareModelMap 类型使其指向同一 map 对象
BindingAwareModelMap 底层支持两种接口 (Map&Model) 推荐使用 Map 便于框架移植
来源: https://www.cnblogs.com/Open-ing/p/12185441.html