记录一下SpringMVC的学习

第0章 SpringMVC框架的核心内容

1.SpringMVC 概述
2.SpringMVC 的 HelloWorld
3.使用 @RequestMapping 映射请求
4.映射请求参数 & 请求头
5.处理模型数据
6.视图和视图解析器
7.RESTful CRUD
8.SpringMVC 表单标签 & 处理静态资源 9.处理 JSON:使用 HttpMessageConverter
10.文件的上传
11.使用拦截器
12.SpringMVC 运行流程
13.在 Spring 的环境下使用 SpringMVC

第1章 SpringMVC 概述

1.1SpringMVC 概述

1)Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的
MVC 框架之一
2)Spring3.0 后全面超越 Struts2,成为最优秀的 MVC 框架。
3)Spring MVC 通过一套 MVC 注解,让 POJO 成为处理请求的控制器,而无须实现任
何接口。
4)支持 REST 风格的 URL 请求。
5)采用了松散耦合可插拔组件结构,比其他 MVC 框架更具扩展性和灵活性。

1.2 SpringMVC是什么

1)一种轻量级的、基于MVC的Web层应用框架。偏前端而不是基于业务逻辑层。Spring框架的一个后续产品。
2)Spring框架结构图(新版本):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K09CqbUl-1594558772635)(/Users/mac/Documents/寒假学习/大数据/SpringMVC/SpringMVC笔记/wpsbjeKdo.jpg)]

1.3 SpringMVC能干什么

1)天生与Spring框架集成,如:(IOC,AOP)
2)支持Restful风格
3)进行更简洁的Web层开发
4)支持灵活的URL到页面控制器的映射
5)非常容易与其他视图技术集成,如:Velocity、FreeMarker等等
6)因为模型数据不存放在特定的API里,而是放在一个Model里(Map数据结构实现,因此很容易被其他框架使用)
7)非常灵活的数据验证、格式化和数据绑定机制、能使用任何对象进行数据绑定,不必实现特定框架的API
8)更加简单、强大的异常处理
9)对静态资源的支持
10)支持灵活的本地化、主题等解析

1.4 SpringMVC怎么玩

1)将Web层进行了职责解耦,基于请求-响应模型
2)常用主要组件
①DispatcherServlet:前端控制器
②Controller:处理器/页面控制器,做的是MVC中的C的事情,但控制逻辑转移到前端控制器了,用于对请求进行处理
③HandlerMapping :请求映射到处理器,找谁来处理,如果映射成功返回一个HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器对象)
④View Resolver : 视图解析器,找谁来处理返回的页面。把逻辑视图解析为具体的View,进行这种策略模式,很容易更换其他视图技术;
如InternalResourceViewResolver将逻辑视图名映射为JSP视图
⑤LocalResolver:本地化、国际化
⑥MultipartResolver:文件上传解析器
⑦HandlerExceptionResolver:异常处理器

1.5 永远的HelloWorld

Springmvc的HelloWorld:

  1. 创建web工程, 导入核心的jar包.
  2. 在web.xml中配置SpringMVC的前端控制器: DispatcherServlet
  3. 配置SpringMVC的核心配置文件: springmvc.xml
  4. 编写请求处理器
  5. 浏览器端发送请求, 请求处理器中处理请求
  6. 测试

Springmvc HelloWorld 执行流程:

  1. 启动Tomcat服务器, 会加载DispatcherServlet, 然后就会读取springmvc.xml,进而创建好的Springmvc容器对象.
    创建Springmvc容器对象: 组件扫描会 扫描到请求处理器, 以及请求处理中@RequestMapping注解,
    能得到具体的请求与请求处理器 中方法的映射。

  2. 客户端发送请求: http://localhost:8888/Springmvc01/hello

  3. 请求到达web.xml中与进行匹配, 匹配成功,就将请求交给DispatcherServlet

  4. DispatcherServlet根据请求 与 请求处理方法的映射, 将请求交给具体的请求处理器中的请求处理方法来进行处理

  5. 请求处理方法处理完请求, 最终方法会返回一个字符串

  6. 视图解析器根据请求处理方法返回的结果, prefix + returnValue + suffix, 解析生成具体的物理视图路径,
    再通过转发的方式去往视图。

·

1) 新建Web工程,加入 jar 包

spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2) 在 web.xml 中配置 DispatcherServlet

<!-- 配置SpringMVC核心控制器: -->
<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

① 解释配置文件的名称定义规则:

实际上也可以不通过 contextConfigLocation 来配置 SpringMVC 的配置文件, 而使用默认的.默认的配置文件为: `/WEB-INF/<servlet-name>-servlet.xml`

3) 加入 Spring MVC 的配置文件:springmvc.xml

① 增加配置

<!-- 设置扫描组件的包: -->
<context:component-scan base-package="com.atguigu.springmvc"/><!-- 配置映射解析器:如何将控制器返回的结果字符串,转换为一个物理的视图文件-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>

4) 需要创建一个入口页面,index.jsp

<a href="${pageContext.request.contextPath }/helloworld">Hello World</a>

可以是:

<a href="hello">Hello World</a>

5) 编写处理请求的处理器,并标识为处理器

package com.atguigu.springmvc.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller  //声明Bean对象,为一个控制器组件
public class HelloWorldController {/*** 映射请求的名称:用于客户端请求;类似Struts2中action映射配置的action名称* 1. 使用 @RequestMapping 注解来映射请求的 URL* 2. 返回值会通过视图解析器解析为实际的物理视图, 对于 InternalResourceViewResolver 视图解析器, * 会做如下的解析:*                 通过 prefix + returnVal + suffix 这样的方式得到实际的物理视图, 然后做转发操作.*                 /WEB-INF/views/success.jsp*/
@RequestMapping(value="/helloworld",method=RequestMethod.GET)
public String helloworld(){System.out.println("hello,world");return "success"; //结果如何跳转呢?需要配置映射解析器
}        
}

6) 编写视图

/WEB-INF/views/success.jsp
<h4>Sucess Page</h4>

7) 部署测试:

http://localhost:8080/SpringMVC/index.jsp

1.6 HelloWorld深度解析

1.6.1 HelloWorld请求流程图解:

在这里插入图片描述

1.6.2 一般请求的映射路径名称和处理请求的方法名称最好一致(实质上方法名称任意)

@RequestMapping(value="/helloworld",method=RequestMethod.GET)
public String helloworld(){
//public String abc123(){
System.out.println("hello,world");
return "success";
}
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>

1.6.3 处理请求方式有哪几种

public enum RequestMethod {
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE
}

1.6.4 @RequestMapping可以应用在什么地方

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {}

1.6.5 流程分析:

在这里插入图片描述

基本步骤:
①客户端请求提交到DispatcherServlet
②由DispatcherServlet控制器查询一个或多个HandlerMapping,找到处理请求的Controller
③DispatcherServlet将请求提交到Controller(也称为Handler)
④Controller调用业务逻辑处理后,返回ModelAndView
⑤DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图
⑥视图负责将结果显示到客户端

第2章 @RequestMapping注解

2.1 @RequestMapping 映射请求注解

2.1.1 @RequestMapping 概念

1)SpringMVC使用@RequestMapping注解为控制器指定可以处理哪些 URL 请求
2)在控制器的类定义及方法定义处都可标注 @RequestMapping
①标记在类上:提供初步的请求映射信息。相对于 WEB 应用的根目录
②标记在方法上:提供进一步的细分映射信息。相对于标记在类上的 URL
3)若类上未标注 @RequestMapping,则方法处标记的 URL 相对于 WEB 应用的根目录
4) 作用:DispatcherServlet 截获请求后,就通过控制器上 @RequestMapping 提供的映射信息确定请求所对应的处理方法。

2.1.2 @ RequestMapping源码参考

package org.springframework.web.bind.annotation;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String[] value() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}

2.2 RequestMapping 可标注的位置

2.2.1 实验代码

定义页面链接、控制器方法

<a href="springmvc/helloworld">test @RequestMapping</a>
@Controller  //声明Bean对象,为一个控制器组件
@RequestMapping("/springmvc")
public class HelloWorldController {
/*** 映射请求的名称:用于客户端请求;类似Struts2中action映射配置的,action名称*1 使用@RequestMapping 注解来映射请求的 URL*2 返回值会通过视图解析器解析为实际的物理视图, 
*  对于 InternalResourceViewResolver 视图解析器, *  会做如下的解析:*  通过 prefix + returnVal + 后缀 这样的方式得到实际的物理视图, 然会做转发操作.* /WEB-INF/views/success.jsp*/
@RequestMapping(value="/helloworld")
public String helloworld(){
System.out.println("hello,world");
return "success"; //结果如何跳转呢?需要配置视图解析器
}        
}

2.3 RequestMapping映射请求方式

2.3.1 标准的 HTTP 请求报头

在这里插入图片描述

2.3.2 映射请求参数、请求方法或请求头

  • 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,param2参数的值无限制

2.3.3 实验代码

1)定义控制器方法

@Controller
@RequestMapping("/springmvc")
public class SpringMVCController {
@RequestMapping(value="/testMethord",method=RequestMethod.POST)
public String testMethord(){
System.out.println("testMethord...");
return "success";
}
}

2) 以get方式请求

<a href="springmvc/testMethord">testMethord</a>

3) 以POST方式请求

<form action="springmvc/testMethord" method="post">
<input type="submit" value="submit">
</form>

2.4 RequestMapping映射请求参数&请求头

2.4.1 RequestMapping_请求参数&请求头【了解】

//了解: 可以使用 params 和 headers 来更加精确的映射请求. params 和 headers 支持简单的表达式.
@RequestMapping(value="/testParamsAndHeaders",
params= {"username","age!=10"}, headers = { "Accept-Language=en-US,zh;q=0.8" })
public String testParamsAndHeaders(){
System.out.println("testParamsAndHeaders...");
return "success";
}

2.5 RequestMapping映射请求占位符PathVariable注解

2.5.1 @PathVariable

带占位符的 URL 是 Spring3.0 新增的功能,该功能在 SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:
URL 中的 {xxx} 占位符可以通过 @PathVariable("xxx") 绑定到操作方法的入参中。

2.5.2 实验代码

  • 定义控制器方法
//@PathVariable 注解可以将请求URL路径中的请求参数,传递到处理请求方法的入参中
@RequestMapping(value="/testPathVariable/{id}")
public String testPathVariable(@PathVariable("id") Integer id){
System.out.println("testPathVariable...id="+id);
return "success";
}
  • 请求链接
<!-- 测试 @PathVariable -->
<a href="springmvc/testPathVariable/1">testPathVariable</a>

第3章 REST

3.1参考资料:

1)理解本真的REST架构风格: http://kb.cnblogs.com/page/186516/
2)REST: http://www.infoq.com/cn/articles/rest-introduction

3.2REST是什么?

1)REST:即 Representational State Transfer。(资源)表现层状态转化。是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用

  • ①资源(Resources):网络上的一个实体,或者说是网络上的一个具体信息。
    它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的存在。
    可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的 URI 。
    获取这个资源,访问它的URI就可以,因此 URI 即为每一个资源的独一无二的识别符。
  • ②表现层(Representation):把资源具体呈现出来的形式,叫做它的表现层(Representation)。比如,文本可以用 txt 格式表现,也可以用 HTML 格式、XML 格式、JSON 格式表现,甚至可以采用二进制格式。
  • ③状态转化(State Transfer):每发出一个请求,就代表了客户端和服务器的一次交互过程。HTTP协议,是一个无状态协议,即所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生“状态转化”(State Transfer)
    而这种转化是建立在表现层之上的,所以就是 “表现层状态转化”。
  • ④具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。
    它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

2)URL风格

示例:

  • order/1 HTTP GET :得到 id = 1 的 order
  • order/1 HTTP DELETE:删除 id = 1的 order
  • order HTTP PUT:更新order
  • order HTTP POST:新增 order

3)HiddenHttpMethodFilter
浏览器 form 表单只支持 GET 与 POST 请求,而DELETE、PUT 等 method 并不
支持,Spring3.0 添加了一个过滤器,可以将这些请求转换为标准的 http 方法,使
得支持 GET、POST、PUT 与 DELETE 请求。

3.3 HiddenHttpMethodFilter过滤器源码分析

1) 为什么请求隐含参数名称必须叫做”_method”

在这里插入图片描述

2) hiddenHttpMethodFilter 的处理过程

在这里插入图片描述

在这里插入图片描述

3.4 实验代码

1)配置HiddenHttpMethodFilter过滤器

<!-- 支持REST风格的过滤器:可以将POST请求转换为PUT或DELETE请求 -->
<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>

2) 代码

/*** 1.测试REST风格的  GET,POST,PUT,DELETE 操作* 以CRUD为例:* 新增: /order POST* 修改: /order/1 PUT           update?id=1* 获取: /order/1 GET                get?id=1* 删除: /order/1 DELETE        delete?id=1* 2.如何发送PUT请求或DELETE请求?* ①.配置HiddenHttpMethodFilter* ②.需要发送POST请求* ③.需要在发送POST请求时携带一个 name="_method"的隐含域,值为PUT或DELETE* 3.在SpringMVC的目标方法中如何得到id值呢?*   使用@PathVariable注解*/
@RequestMapping(value="/testRESTGet/{id}",method=RequestMethod.GET)
public String testRESTGet(@PathVariable(value="id") Integer id){
System.out.println("testRESTGet id="+id);
return "success";
}@RequestMapping(value="/testRESTPost",method=RequestMethod.POST)
public String testRESTPost(){
System.out.println("testRESTPost");
return "success";
}@RequestMapping(value="/testRESTPut/{id}",method=RequestMethod.PUT)
public String testRESTPut(@PathVariable("id") Integer id){
System.out.println("testRESTPut id="+id);
return "success";
}@RequestMapping(value="/testRESTDelete/{id}",method=RequestMethod.DELETE)
public String testRESTDelete(@PathVariable("id") Integer id){
System.out.println("testRESTDelete id="+id);
return "success";
}

3) 请求链接

<!-- 实验1 测试 REST风格 GET 请求 -->
<a href="springmvc/testRESTGet/1">testREST GET</a><br/><br/><!-- 实验2 测试 REST风格 POST 请求 -->
<form action="springmvc/testRESTPost" method="POST">
<input type="submit" value="testRESTPost">
</form><!-- 实验3 测试 REST风格 PUT 请求 -->
<form action="springmvc/testRESTPut/1" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="testRESTPut">
</form><!-- 实验4 测试 REST风格 DELETE 请求 -->
<form action="springmvc/testRESTDelete/1" method="POST">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="testRESTDelete">
</form>

第4章 处理请求数据

4.1请求处理方法签名

  • 1)Spring MVC 通过分析处理方法的签名(方法的名字+参数列表),HTTP请求信息绑定到处理方法的相应形参中。
  • 2)Spring MVC 对控制器处理方法签名的限制是很宽松的,几乎可以按喜欢的任何方式对方法进行签名。
  • 3)必要时可以对方法及方法入参标注相应的注解( @PathVariable 、@RequestParam、@RequestHeader 等)、
  • 4)Spring MVC 框架会将 HTTP 请求的信息绑定到相应的方法入参中,并根据方法的返回值类型做出相应的后续处理。

4.2 @RequestParam注解

  • 1)在处理方法入参处使用 @RequestParam 可以把请求参数传递给请求方法
  • 2)value:参数名
  • 3)required:是否必须。默认为 true, 表示请求参数中必须包含对应的参数,若不存在,将抛出异常
  • 4)defaultValue: 默认值,当没有传递参数时使用该值

4.2.1 实验代码

1) 增加控制器方法

/*** @RequestParam 注解用于映射请求参数*         value 用于映射请求参数名称*         required 用于设置请求参数是否必须的*         defaultValue 设置默认值,当没有传递参数时使用该值*/
@RequestMapping(value="/testRequestParam")
public String testRequestParam(
@RequestParam(value="username") String username,
@RequestParam(value="age",required=false,defaultValue="0") int age){
System.out.println("testRequestParam - username="+username +",age="+age);
return "success";
}

2) 增加页面链接

<!--测试 请求参数 @RequestParam 注解使用 -->
<a href="springmvc/testRequestParam?username=learn&age=10">testRequestParam</a>

4.3 @RequestHeader 注解

  • 1)使用 @RequestHeader 绑定请求报头的属性值
  • 2)请求头包含了若干个属性,服务器可据此获知客户端的信息,通过 @RequestHeader 即可将请求头中的属性值绑定到处理方法的入参中

在这里插入图片描述

4.3.1 实验代码

//了解: 映射请求头信息 用法同 @RequestParam
@RequestMapping(value="/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="Accept-Language") String al){
System.out.println("testRequestHeader - Accept-Language:"+al);
return "success";
}
<!-- 测试 请求头@RequestHeader 注解使用 -->
<a href="springmvc/testRequestHeader">testRequestHeader</a>

4.4 @CookieValue 注解

  • 1)使用 @CookieValue 绑定请求中的 Cookie 值
  • 2)@CookieValue 可让处理方法入参绑定某个 Cookie 值

在这里插入图片描述

4.4.1实验代码

1) 增加控制器方法

//了解:@CookieValue: 映射一个 Cookie 值. 属性同 @RequestParam
@RequestMapping("/testCookieValue")
public String testCookieValue(@CookieValue("JSESSIONID") String sessionId) {
System.out.println("testCookieValue: sessionId: " + sessionId);
return "success";
}

2)增加页面链接

<!--测试 请求Cookie @CookieValue 注解使用 -->
<a href="springmvc/testCookieValue">testCookieValue</a>

4.5 使用POJO作为参数

  • 1)使用 POJO 对象绑定请求参数值
  • 2)Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配,自动为该对象填充属性值。支持级联属性。如:dept.deptId、dept.address.tel 等
  • 3)请求参数必须和必须和实体类中的成员变量名相同,且必须提供get set方法

4.5.1实验代码

1) 增加控制器方法、表单页面

/*** Spring MVC 会按请求参数名和 POJO 属性名进行自动匹配, 自动为该对象填充属性值。* 支持级联属性*                 如:dept.deptId、dept.address.tel 等*/
@RequestMapping("/testPOJO")
public String testPojo(User user) {
System.out.println("testPojo: " + user);
return "success";
}
<form action="testPOJO" method="post">用户名称: <input type="text" name="username"/><br/>用户密码: <input type="password" name="password"/><br/>用户邮箱: <input type="text" name="email"/><br/>用户性别: 男 <input type="radio" name="gender" value="1"/><input type="radio" name="gender" value="0"/><br/><!-- 支持级联的方式 -->用户省份: <input type="text" name="address.province" /><br/>用户城市: <input type="text" name="address.city"/><br/><input type="submit" value="注册"/></form>

在这里插入图片描述

2) 增加实体类

package com.atguigu.springmvc.entities;public class Address {private String province;
private String city;//get/set }	
package com.atguigu.springmvc.entities;public class User {
private Integer id ;
private String username;
private String password;private String email;
private int age;private Address address;//get/set 
}

3)如果中文有乱码,需要配置字符编码过滤器,且配置其他过滤器之前,
如(HiddenHttpMethodFilter),否则不起作用。(思考method=”get”请求的乱码问题怎么解决的)

	<!-- 配置字符集 --><filter><filter-name>encodingFilter</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>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

4.6 使用Servlet原生API作为参数

1)MVC 的 Handler 方法可以接受哪些 ServletAPI 类型的参数

  • 1)HttpServletRequest
  • 2)HttpServletResponse
  • 3)HttpSession
  • 4)java.security.Principal
  • 5)Locale
  • 6)InputStream
  • 7)OutputStream
  • 8)Reader
  • 9)Writer

4.6.1 实验代码

/*** 可以使用 Serlvet 原生的 API 作为目标方法的参数 具体支持以下类型* * HttpServletRequest * HttpServletResponse * HttpSession* java.security.Principal * Locale InputStream * OutputStream * Reader * Writer* @throws IOException */
@RequestMapping("/testServletAPI")
public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException {
System.out.println("testServletAPI, " + request + ", " + response);
out.write("hello springmvc");
//return "success";
}
<!-- 测试 Servlet API 作为处理请求参数 -->
<a href="springmvc/testServletAPI">testServletAPI</a>

第5章 处理响应数据

5.1 SpringMVC 输出模型数据概述

5.1.1提供了以下几种途径输出模型数据

  • 1)ModelAndView: 处理方法返回值类型为 ModelAndView 时, 方法体即可通过该对象添加模型数据

  • 2)Map 及 Model: 入参为 org.springframework.ui.Model、
    org.springframework.ui.ModelMap 或 java.uti.Map 时,处理方法返回时,Map 中的数据会自动添加到模型中。

5.2处理模型数据之 ModelAndView

5.2.1ModelAndView介绍

  • 1)控制器处理方法的返回值如果为 ModelAndView, 则其既包含视图信息,也包含模型数据信息。
  • 2)添加模型数据:
    MoelAndView addObject(String attributeName, Object attributeValue)
    ModelAndView addAllObject(Map<String, ?> modelMap)
  • 3)设置视图:
    void setView(View view)
    void setViewName(String viewName)

5.2.2 实验代码

1)增加控制器方法

/*** 目标方法的返回类型可以是ModelAndView类型*                 其中包含视图信息和模型数据信息*/
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
System.out.println("testModelAndView");
String viewName = "success";
ModelAndView mv = new ModelAndView(viewName);
mv.addObject("time",new Date().toString()); //实质上存放到request域中 
return mv;
}

2)增加页面链接

<!--测试 ModelAndView 作为处理返回结果 -->
<a href="testModelAndView">testModelAndView</a>

3)增加成功页面,显示数据

time: ${requestScope.time }

4) 断点调试

断点调试

5.2.2 源码解析

1
2
3
4
5
6

5.3 处理模型数据之 Map

5.3.1Map介绍

  • 1)Spring MVC 在内部使用了一个 org.springframework.ui.Model 接口存储模型数据
    具体使用步骤
  • 2)Spring MVC 在调用方法前会创建一个隐含的模型对象作为模型数据的存储容器。
  • 3)如果方法的入参为 Map 或 Model 类型,Spring MVC 会将隐含模型的引用传递给这些入参。
  • 4)在方法体内,开发者可以通过这个入参对象访问到模型中的所有数据,也可以向模型中添加新的属性数据
    在这里插入图片描述
    在这里插入图片描述
    ExtendedModelMap和BindingAwareModelMap都实现了接口ModelMap

5.3.2 实验代码

1)增加控制器方法

结论:
SpringMVC会把Map中的模型数据存放到request域对象中.
SpringMVC再调用完请求处理方法后,不管方法的返回值是什么类型,都会处理成一个ModelAndView对象(参考DispatcherServlet的945行)

/*** Map* 结论: SpringMVC会把Map中的模型数据存放到request域对象中.*      SpringMVC再调用完请求处理方法后,不管方法的返回值是什么类型,都会处理成一个ModelAndView对象(参考DispatcherServlet的945行)* */		@RequestMapping("/testMap")public String  testMap(Map<String,Object> map ) {//模型数据: password=123456System.out.println(map.getClass().getName()); //BindingAwareModelMapmap.put("password", "123456");return "success";}

2)增加页面链接

<!-- 测试 Map 作为处理返回结果 -->
<a href="testMap">testMap</a>

3)增加成功页面,显示结果

names: ${requestScope.names }

4)显示结果截图

结果截图

5)注意问题:Map集合的泛型,key为String,Value为Object,而不是String
6)测试参数类型

//目标方法的返回类型也可以是一个Map类型参数(也可以是Model,或ModelMap类型)
@RequestMapping("/testMap2")
public String testMap2(Map<String,Object> map,Model model,ModelMap modelMap){
System.out.println(map.getClass().getName());
map.put("names", Arrays.asList("Tom","Jerry","Kite"));
model.addAttribute("model", "org.springframework.ui.Model");
modelMap.put("modelMap", "org.springframework.ui.ModelMap");System.out.println(map == model);
System.out.println(map == modelMap);
System.out.println(model == modelMap);System.out.println(map.getClass().getName());
System.out.println(model.getClass().getName());
System.out.println(modelMap.getClass().getName());/*
true
true
true
org.springframework.validation.support.BindingAwareModelMap
org.springframework.validation.support.BindingAwareModelMap
org.springframework.validation.support.BindingAwareModelMap*/ 
return "success";
}

在这里插入图片描述

8) 推荐:Map, 便于框架移植。
9)源码参考

public class BindingAwareModelMap extends ExtendedModelMap {@Override
public Object put(String key, Object value) {
removeBindingResultIfNecessary(key, value);
return super.put(key, value);
}@Override
public void putAll(Map<? extends String, ?> map) {
for (Map.Entry<? extends String, ?> entry : map.entrySet()) {
removeBindingResultIfNecessary(entry.getKey(), entry.getValue());
}
super.putAll(map);
}private void removeBindingResultIfNecessary(Object key, Object value) {
if (key instanceof String) {
String attributeName = (String) key;
if (!attributeName.startsWith(BindingResult.MODEL_KEY_PREFIX)) {
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attributeName;
BindingResult bindingResult = (BindingResult) get(bindingResultKey);
if (bindingResult != null && bindingResult.getTarget() != value) {
remove(bindingResultKey);
}
}
}
}
}

第6章 视图解析

6.1 SpringMVC如何解析视图概述

1)不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转。
视图对象进行重定向等后续处理

数据流转

2)视图解析源码分析:重要的两个接口

接口1View

接口2ViewResolver

3)断点调试源码

在这里插入图片描述

4) 流程图

在这里插入图片描述

6.2 视图和视图解析器

  • 1)请求处理方法执行完成后,最终返回一个 ModelAndView 对象。对于那些返回 String,View 或 ModeMap 等类型的处理方法,Spring MVC 也会在内部将它们装配成一个 ModelAndView 对象,它包含了逻辑名和模型对象的视图
  • 2)Spring MVC 借助视图解析器(ViewResolver)得到最终的视图对象(View),最终的视图可以是 JSP ,也可能是 Excel、JFreeChart等各种表现形式的视图
  • 3)对于最终究竟采取何种视图对象对模型数据进行渲染,处理器并不关心,处理器工作重点聚焦在生产模型数据的工作上,从而实现 MVC 的充分解耦

6.3 视图

1)视图的作用是渲染模型数据,将模型里的数据以某种形式呈现给客户,主要就是完成转发或者是重定向的操作.
2)为了实现视图模型和具体实现技术的解耦,Spring 在 org.springframework.web.servlet 包中定义了一个高度抽象的 View 接口:

View

3)视图对象由视图解析器负责实例化。由于视图是无状态的,所以他们不会有线程安全的问题

6.4 常用的视图实现类

视图实现类

6.5 JstlView

  • 1)若项目中使用了JSTL,则SpringMVC 会自动把视图由InternalResourceView转为 JstlView (断点调试,将JSTL的jar包增加到项目中,视图解析器会自动修改为JstlView)
  • 2)若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

在这里插入图片描述

6.5.1 实验代码

1)增加jstl标签 jar包(断点调试,这时的View对象就是JstlView)

Jstl

6.6 视图解析器

  • 1)SpringMVC 为逻辑视图名的解析提供了不同的策略,可以在 Spring WEB 上下文中配置一种或多种解析策略,并指定他们之间的先后顺序。每一种映射策略对应一个具体的视图解析器实现类。
  • 2)视图解析器的作用比较单一:将逻辑视图解析为一个具体的视图对象
  • 3)所有的视图解析器都必须实现 ViewResolver 接口:

ViewResolver

6.7 常用的视图解析器实现类

在这里插入图片描述

1)程序员可以选择一种视图解析器或混用多种视图解析器
2)每个视图解析器都实现了 Ordered 接口并开放出一个 order 属性,可以通过 order 属性指定解析器的优先顺序,order 越小优先级越高。
3)SpringMVC 会按视图解析器顺序的优先顺序对逻辑视图名进行解析,直到解析成功并返回视图对象,否则将抛出 ServletException 异常
4)InternalResourceViewResolver
①JSP 是最常见的视图技术,可以使用 InternalResourceViewResolve作为视图解析器:

在这里插入图片描述

6.8mvc:view-controller标签

1)若希望直接响应通过 SpringMVC 渲染的页面,可以使用 mvc:view-controller 标签实现

<!-- 直接配置响应的页面:无需经过控制器来执行结果 -->
<!-- 不经过Handler直接跳转页面 --><mvc:view-controller path="testViewContorller" view-name="success"/> <!-- view-name是对应方法中,返回的那一个字符串--><!-- 使用了view-controlelr以后,会导致RequestMapping的映射失效,因此需要加上 annotation-driven的配置 --><!-- 后面讲 --><mvc:annotation-driven/>

​ 2)请求的路径:

http://localhost:8080/Springmvc02/testViewContorller

3)配置

<mvc:view-controller>

会导致其他请求路径失效
解决办法:

<!-- 在实际开发过程中都需要配置mvc:annotation-driven标签,后面讲,这里先配置上 -->
<mvc:annotation-driven/>

6.9 重定向

  • 1)关于重定向
    ①一般情况下,控制器方法返回字符串类型的值会被当成逻辑视图名处理
    ②如果返回的字符串中带 forward: 或 redirect: 前缀时,SpringMVC 会对他们进行特殊处理:将 forward: 和 redirect: 当成指示符,其后的字符串作为 URL 来处理
    ③redirect:success.jsp:会完成一个到 success.jsp 的重定向的操作
    ④forward:success.jsp:会完成一个到 success.jsp 的转发操作
  • 2)定义页面链接
<a href="springmvc/testRedirect">testRedirect</a>
  • 3)定义控制器方法
	/*** 重定向*/@RequestMapping("/testRedirectView")public String testRedirectView() {return "redirect:/ok.jsp";}//return "forward:/index.jsp";}

4)源码分析:重定向原理

1.源码分析:重定向原理

重定向原理

2

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

return "forward:/index.jsp"

在这里插入图片描述

第7章 综合案例RESTRUL_CRUD

7.1 RESTRUL_CRUD_需求

7.1.1 显示所有员工信息

1)URI:emps
2)请求方式:GET
3)显示效果
在这里插入图片描述

7.1.2 添加操作-去往添加页面

1)显示添加页面:
2)URI:emp
3)请求方式:GET
4)显示效果

在这里插入图片描述

7.1.3 添加操作-添加员工

1)添加员工信息:
2)URI:emp
3)请求方式:POST
4)显示效果:完成添加,重定向到 list 页面。

在这里插入图片描述

7.1.4 删除操作

1)URL:emp/{id}
2)请求方式:DELETE
3)删除后效果:对应记录从数据表中删除

7.1.5 修改操作-去往修改页面

1)URI:emp/{id}
2)请求方式:GET
3)显示效果:回显表单。

7.1.6 修改操作-修改员工

1)URI:emp
2)请求方式:PUT
3)显示效果:完成修改,重定向到 list 页面。

7.1.7 相关的类

省略了Service层,为了教学方便
1)实体类:Employee、Department
2)Handler:EmployeeHandler

3)Dao:EmployeeDao、DepartmentDao

在这里插入图片描述

7.1.8 相关的页面

1)list.jsp
2)input.jsp
3)edit.jsp

7.2 搭建开发环境

1) 拷贝jar包

com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
spring-aop-4.0.0.RELEASE.jar
spring-aspects-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
spring-jdbc-4.0.0.RELEASE.jar
spring-orm-4.0.0.RELEASE.jar
spring-tx-4.0.0.RELEASE.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2) 创建配置文件:springmvc.xml 增加context,mvc,beans名称空间。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 配置扫描的包:com.atguigu.springmvc.crud -->
<context:component-scan base-package="com.atguigu.springmvc"/><!-- 配置视图解析器:默认采用转发 -->
<bean id="internalResourceViewResolver" 
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"></property>
</bean> 
</beans>

3)配置核心控制器:web.xml

<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet> 
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

4)将 POST 请求转换为 PUT 或 DELETE 请求

  <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>

5)创建相关页面

/WEB-INF/views/list.jsp
index.jsp

6)增加实体类

在这里插入图片描述
7)增加DAO类
EmployeeDao

package com.atguigu.springmvc.crud.dao;import java.util.Collection;
import java.util.HashMap;
import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;import com.atguigu.springmvc.crud.entities.Department;
import com.atguigu.springmvc.crud.entities.Employee;@Repository
public class EmployeeDao {private static Map<Integer, Employee> employees = null;@Autowired
private DepartmentDao departmentDao;static{
employees = new HashMap<Integer, Employee>();employees.put(1001, new Employee(1001, "E-AA", "aa@163.com", 1, new Department(101, "D-AA")));
employees.put(1002, new Employee(1002, "E-BB", "bb@163.com", 1, new Department(102, "D-BB")));
employees.put(1003, new Employee(1003, "E-CC", "cc@163.com", 0, new Department(103, "D-CC")));
employees.put(1004, new Employee(1004, "E-DD", "dd@163.com", 0, new Department(104, "D-DD")));
employees.put(1005, new Employee(1005, "E-EE", "ee@163.com", 1, new Department(105, "D-EE")));
}private static Integer initId = 1006;public void save(Employee employee){
if(employee.getId() == null){
employee.setId(initId++);
} 
employee.setDepartment(departmentDao.getDepartment(
employee.getDepartment().getId()));
employees.put(employee.getId(), employee);
}public Collection<Employee> getAll(){
return employees.values();
}public Employee get(Integer id){
return employees.get(id);
}public void delete(Integer id){
employees.remove(id);
}
}	

DepartmentDao

package com.atguigu.springmvc.crud.dao;import java.util.Collection;
import java.util.HashMap;
import java.util.Map;import org.springframework.stereotype.Repository;import com.atguigu.springmvc.crud.entities.Department;@Repository
public class DepartmentDao {private static Map<Integer, Department> departments = null;static{
departments = new LinkedHashMap<Integer, Department>();departments.put(101, new Department(101, "D-AA"));
departments.put(102, new Department(102, "D-BB"));
departments.put(103, new Department(103, "D-CC"));
departments.put(104, new Department(104, "D-DD"));
departments.put(105, new Department(105, "D-EE"));
}public Collection<Department> getDepartments(){
return departments.values();
}public Department getDepartment(Integer id){
return departments.get(id);
}}

7.3 RESTRUL_CRUD_显示所有员工信息

1) 增加页面链接

<a href="empList">To Employee List</a>

2)增加处理器

package com.atguigu.springmvc.crud.handlers;import java.util.Map;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;import com.atguigu.springmvc.crud.dao.EmployeeDao;@Controller
public class EmployeeHandler {@Autowired
private EmployeeDao employeeDao ;@RequestMapping("/empList")
public String empList(Map<String,Object> map){
map.put("empList", employeeDao.getAll());        //默认存放到request域中        
return "list";
} 
}

3) SpringMVC中没遍历的标签,需要使用jstl标签进行集合遍历增加jstl标签库jar包

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><c:if test="${empty requestScope.empList }">
对不起,没有找到任何员工!
</c:if>
<c:if test="${!empty requestScope.empList }">
<table border="1" cellpadding="10" cellspacing="0">                
<tr>
<td>EmpId</td>
<td>LastName</td>
<td>Gender</td>
<td>Email</td>
<td>DepartmentName</td>
<td>Edit</td>
<td>Delete</td>
</tr>
<c:forEach items="${requestScope.empList }" var="emp">
<tr>
<td>${emp.id }</td>
<td>${emp.lastName }</td>
<td>${emp.gender==0?"Female":"Male" }</td>
<td>${emp.email }</td>
<td>${emp.department.departmentName }</td>
<td><a href="">Edit</a></td>
<td><a href="">Delete</a></td>
</tr>                
</c:forEach>        
</table>
</c:if></body>
</html>

7.4 RESTRUL_CRUD_添加操作

1) 在list.jsp上增加连接

<a href="empInput">Add Employee</a>

2) 增加处理器方法

@RequestMapping(value="/empInput",method=RequestMethod.GET)
public String empInput(Map<String,Object> map){
map.put("deptList", departmentDao.getDepartments());
//解决错误:java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute
Employee employee = new Employee();
//map.put("command", employee);
map.put("employee", employee);
return "add";
}

3)显示添加页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 
Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。--><form:form action="empAdd" method="POST" modelAttribute="employee">LastName : <form:input path="lastName"/><br><br>Email : <form:input path="email"/><br><br><%Map<String,String> map = new HashMap<String,String>();map.put("1", "Male");map.put("0","Female");request.setAttribute("genders", map);%>Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>DeptName : <form:select path="department.id" items="${deptList }" itemLabel="departmentName" itemValue="id"></form:select><br><br><input type="submit" value="Submit"><br><br></form:form> 
</body>
</html>

4)显示表单信息时,会报错:

HTTP Status 500 - type Exception report
message 
description The server encountered an internal error () that prevented it from fulfilling this request.
exception 
org.apache.jasper.JasperException: An exception occurred processing JSP page /WEB-INF/views/add.jsp at line 18
15:                         ② 表单回显
16:          -->
17:          <form:form action="empAdd" method="POST">
18:                  LastName : <form:input path="lastName"/>
19:                  Email : <form:input path="email"/>
20:                  <%
21:                          Map<String,String> map = new HashMap<String,String>();
Stacktrace:org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:505)org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:410)org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:337)org.apache.jasper.servlet.JspServlet.service(JspServlet.java:266)javax.servlet.http.HttpServlet.service(HttpServlet.java:803)org.springframework.web.servlet.view.InternalResourceView.renderMergedOutputModel(InternalResourceView.java:209)org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:266)org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1225)org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1012)org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:876)org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:931)org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:822)javax.servlet.http.HttpServlet.service(HttpServlet.java:690)org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:807)javax.servlet.http.HttpServlet.service(HttpServlet.java:803)org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:108)
root cause 
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attributeorg.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)

7.5 使用Spring的表单标签

  • 1)通过 SpringMVC 的表单标签可以实现将模型数据中的属性和 HTML 表单元素相绑定,以实现表单数据更便捷编辑和表单值的回显

  • 2)form 标签
    一般情况下,通过 GET 请求获取表单页面,而通过 POST 请求提交表单页面,因此获取表单页面和提交表单页面的 URL 是相同的。
    只要满足该最佳条件的契约,form:form 标签就无需通过 action 属性指定表单提交的 URL
    可以通过 modelAttribute 属性指定绑定的模型属性,若没有指定该属性,则默认从 request 域对象中读取 command 的表单 bean,如果该属性值也不存在,则会发生错误。

  • 3)SpringMVC 提供了多个表单组件标签,如 form:input/form:select/ 等,用以绑定表单字段的属性值,它们的共有属性如下:
    path:表单字段,对应 html 元素的 name 属性,支持级联属性
    htmlEscape:是否对表单值的 HTML 特殊字符进行转换,默认值为 true
    cssClass:表单组件对应的 CSS 样式类名
    cssErrorClass:表单组件的数据存在错误时,采取的 CSS 样式

  • 4)form:input、form:password、form:hidden、form:textarea:对应 HTML 表单的 text、password、hidden、

    textarea 标签

  • 5)form:radiobutton:单选框组件标签,当表单 bean 对应的属性值和 value 值相等时,单选框被选中

  • 6)form:radiobuttons:单选框组标签,用于构造多个单选框
    items:可以是一个 List、String[] 或 Map
    itemValue:指定 radio 的 value 值。可以是集合中 bean 的一个属性值
    itemLabel:指定 radio 的 label 值
    delimiter:多个单选框可以通过 delimiter 指定分隔符

  • 7)form:checkbox:复选框组件。用于构造单个复选框

  • 8)form:checkboxs:用于构造多个复选框。使用方式同 form:radiobuttons 标签

  • 9)form:select:用于构造下拉框组件。使用方式同 form:radiobuttons 标签

  • 10)form:option:下拉框选项组件标签。使用方式同 form:radiobuttons 标签

  • 11)form:errors:显示表单组件或数据校验所对应的错误

    <form:errors path= “*” /> :显示表单所有的错误
    <form:errors path= “user*” /> :显示所有以 user 为前缀的属性对应的错误
    <form:errors path= “username” /> :显示特定表单对象属性的错误
    

7.6 增加员工实验代码

1) 表单

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。--><form:form action="empAdd" method="POST" modelAttribute="employee">LastName : <form:input path="lastName" /><br><br>Email : <form:input path="email" /><br><br><%Map<String,String> map = new HashMap<String,String>();map.put("1", "Male");map.put("0","Female");request.setAttribute("genders", map);%>Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>DeptName : <form:select path="department.id" items="${deptList }" itemLabel="departmentName" itemValue="id"></form:select><br><br><input type="submit" value="Submit"><br><br></form:form> 
</body>
</html>

2) 控制器方法

@Controller
public class EmployeeHandler {
@RequestMapping(value="/empAdd",method=RequestMethod.POST)
public String empAdd(Employee employee){
employeeDao.save(employee);
return "redirect:/empList";
}
}

7.7 RESTRUL_CRUD_删除操作&处理静态资源

7.7.1 删除实验代码

1)页面链接

<td><a href="/empDelete/${emp.id }">Delete</a></td>

2)控制器方法

@RequestMapping(value="/empDelete/{id}" ,method=RequestMethod.DELETE)
public String empDelete(@PathVariable("id") Integer id){
employeeDao.delete(id);
return "redirect:/empList";
}

7.7.2 HiddenHttpMethodFilter过滤器

发起请求,无法执行,因为delete请求必须通过post请求转换为delete请求,借助:HiddenHttpMethodFilter过滤器

7.7.3 需要使用jQuery来转换请求方式

1)加入jQuery库文件

/scripts/jquery-1.9.1.min.js

2)jQuery库文件不起作用

警告: No mapping found for HTTP request with URI [/SpringMVC_03_RESTFul_CRUD/scripts/jquery-1.9.1.min.js] in DispatcherServlet with name ‘springDispatcherServlet’

在这里插入图片描述

3)解决办法,SpringMVC 处理静态资源
①为什么会有这样的问题:
优雅的 REST 风格的资源URL 不希望带 .html 或 .do 等后缀,若将 DispatcherServlet 请求映射配置为 /, 则 Spring MVC 将捕获 WEB 容器的所有请求, 包括静态资源的请求, SpringMVC 会将他们当成一个普通请求处理, 因找不到对应处理器将导致错误。
②解决: 在 SpringMVC 的配置文件中配置 <mvc:default-servlet-handler/>
4)配置后,原来的请求又不好使了
需要配置<mvc:annotation-driven />

7.7.4 关于mvc:default-servlet-handler/作用

<!-- 
<mvc:default-servlet-handler/> 将在 SpringMVC 上下文中定义一个 DefaultServletHttpRequestHandler,
它会对进入 DispatcherServlet 的请求进行筛查,如果发现是没有经过映射的请求,
就将该请求交由 WEB 应用服务器默认的 Servlet 处理,如果不是静态资源的请求,才由 DispatcherServlet 继续处理
一般 WEB 应用服务器默认的 Servlet 的名称都是 default。
若所使用的 WEB 服务器的默认 Servlet 名称不是 default,则需要通过 default-servlet-name 属性显式指定        
参考:CATALINA_HOME/config/web.xml<servlet><servlet-name>default</servlet-name><servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class><init-param><param-name>debug</param-name><param-value>0</param-value></init-param><init-param><param-name>listings</param-name><param-value>false</param-value></init-param><load-on-startup>1</load-on-startup></servlet>
该标签属性default-servlet-name默认值是"default",可以省略。        
<mvc:default-servlet-handler/>        -->
<mvc:default-servlet-handler default-servlet-name="default"/>

7.7.5 通过jQuery转换为DELETE请求

<td><a class="delete" href="empDelete/${emp.id }">Delete</a></td>
<form action="" method="post">
<input type="hidden" name="_method" value="DELETE"/>
</form>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){
$(".delete").click(function(){
var href = $(this).attr("href");
$("form").attr("action",href).submit();
return false ;
});
});
</script>

7.7.6 删除操作流程图解

在这里插入图片描述

7.8 RESTRUL_CRUD_修改操作

7.8.1 根据id查询员工对象,表单回显

1) 页面链接

<td><a href="empEdit/${emp.id }">Edit</a></td>

2)控制器方法

//修改员工 - 表单回显
@RequestMapping(value="/empEdit/{id}",method=RequestMethod.GET)
public String empEdit(@PathVariable("id") Integer id,Map<String,Object> map){
map.put("employee", employeeDao.get(id));
map.put("deptList",departmentDao.getDepartments());
return "edit";
}

3)修改页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8" import="java.util.*"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body><!-- 
1.为什么使用SpringMVC的form标签
① 快速开发
② 表单回显
2.可以通过modelAttribute指定绑定的模型属性,
若没有指定该属性,则默认从request域中查找command的表单的bean
如果该属性也不存在,那么,则会发生错误。
修改功能需要增加绝对路径,相对路径会报错,路径不对--><form:form action="${pageContext.request.contextPath }/empUpdate" 
method="POST" modelAttribute="employee">                        
<%--LastName : <form:input path="lastName" /><br><br>--%><form:hidden path="id"/><input type="hidden" name="_method" value="PUT"><%-- 这里不要使用form:hidden标签,否则会报错。 
<form:hidden path="_method" value="PUT"/>Spring的隐含标签,没有value属性,同时,path指定的值,在模型对象中也没有这个属性(_method),所以回显时会报错。org.springframework.beans.NotReadablePropertyException: Invalid property '_method' of bean class [com.atguigu.springmvc.crud.entities.Employee]: Bean property '_method' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?--%>Email : <form:input path="email" /><br><br><%Map<String,String> map = new HashMap<String,String>();map.put("1", "Male");map.put("0","Female");request.setAttribute("genders", map);%>Gender : <br><form:radiobuttons path="gender" items="${genders }" delimiter="<br>"/><br><br>DeptName : <form:select path="department.id" items="${deptList }" itemLabel="departmentName" itemValue="id"></form:select><br><br><input type="submit" value="Submit"><br><br></form:form>
</body>
</html>

7.8.2 提交表单,修改数据

1)控制器方法

@RequestMapping(value="/empUpdate",method=RequestMethod.PUT)
public String empUpdate(Employee employee){
employeeDao.save(employee);              
return "redirect:/empList";
}

第8章 处理JSON

8.1 返回JSON

1)加入 jar 包:
http://wiki.fasterxml.com/JacksonDownload/ 下载地址
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
2)编写目标方法,使其返回 JSON 对应的对象或集合

@ResponseBody  //SpringMVC对JSON的支持,负责将方法的返回值转化成json字符串,响应给浏览器
@RequestMapping("/testJSON")
public Collection<Employee> testJSON(){
return employeeDao.getAll();
}

3)增加页面代码:index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){ 
$("#testJSON").click(function(){var url = this.href ;
var args = {};
$.post(url,args,function(data){
for(var i=0; i<data.length; i++){
var id = data[i].id;
var lastName = data[i].lastName ;
alert(id+" - " + lastName);
}
});return false ;
});                
});
</script></head>
<body><a href="empList">To Employee List</a>
<br><br><a id="testJSON" href="testJSON">testJSON</a></body>
</html>

4)测试

在这里插入图片描述

8.2 HttpMessageConverter原理

8.2.1 HttpMessageConverter

1)HttpMessageConverter 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息
2)HttpMessageConverter接口定义的方法:
①Boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
②Boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。
③List getSupportMediaTypes():该转换器支持的媒体类型。
④T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型的对象。
⑤void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType。

在这里插入图片描述

package org.springframework.http;import java.io.IOException;
import java.io.InputStream;public interface HttpInputMessage extends HttpMessage {InputStream getBody() throws IOException;}	
package org.springframework.http;import java.io.IOException;
import java.io.OutputStream;public interface HttpOutputMessage extends HttpMessage {OutputStream getBody() throws IOException;}

在这里插入图片描述

3)DispatcherServlet 默认装配 RequestMappingHandlerAdapter ,
而 RequestMappingHandlerAdapter 默认装配如下 HttpMessageConverter:

在这里插入图片描述

4)加入 jackson jar 包后, RequestMappingHandlerAdapter
装配的 HttpMessageConverter 如下:

在这里插入图片描述

默认情况下数组长度是6个;增加了jackson的包,后多个一个

MappingJackson2HttpMessageConverter

在这里插入图片描述

8.3使用HttpMessageConveter完成下载功能

/*** 使用HttpMessageConveter完成下载功能:* * 支持  @RequestBody   @ResponseBody   HttpEntity  ResponseEntity* * 下载的原理:  将服务器端的文件 以流的形式  写到 客户端. * ResponseEntity: 将要下载的文件数据, 以及响应信息封装到ResponseEntity对象中,浏览器端通过解析* 				       发送回去的响应数据, 就可以进行一个下载操作. */@RequestMapping("/download")public ResponseEntity<byte[]> testDownload(HttpSession session ) throws Exception{//将要下载的文件读取成一个字节数据byte [] imgs ;ServletContext sc = session.getServletContext();InputStream in = sc.getResourceAsStream("image/songlaoshi.jpg");imgs = new byte[in.available()] ; in.read(imgs);//将响应数据  以及一些响应头信息封装到ResponseEntity中/** 参数:* 	1. 发送给浏览器端的数据*  2. 设置响应头*  3. 设置响应码*/HttpHeaders  headers = new HttpHeaders();headers.add("Content-Disposition", "attachment;filename=songlaoshi.jpg");HttpStatus statusCode = HttpStatus.OK;  // 200ResponseEntity<byte[]>  re = new ResponseEntity<byte[]>(imgs, headers, statusCode);return re ; }

<mvc:annotation-driven>的作用:

  1. 配置了<mvc:view-controller>
  2. 配置了<mvc:default-servlet-handler>
  3. 处理Json,对HttpMessageConveter的支持
  4. 对数据绑定流程的支持 , 对异常处理的支持等 <mvc:annotation-driven>的原理: 启动一些新的组件对象替换原先旧的组件对象, 从而实现一些新的,更强大的功能

解释: <mvc:default-servlet-handler>① 为什么还要配置<mvc:annotation-driven> ②?

① ② 都没有配置的情况: DispatcherServlet 中handlerAdapters中装配:
HttpRequestHandlerAdapter
SimpleControlleraHandlerAdapter
AnnotationMethodHandlerAdapter

① 配置 ②不配置的情况 :DispatcherServlet 中handlerAdapters中装配: HttpRequestHandlerAdapter
SimpleControlleraHandlerAdapter
① ② 都配置的情况: DispatcherServlet 中handlerAdapters中装配: HttpRequestHandlerAdapter
SimpleControlleraHandlerAdapter
RequestMappingHandlerAdapter

  总结:  在Spring 3.2 之后  ,RequestMappingHandlerAdapter 替换掉了AnnotationMethodHandlerAdapter。

第9章 文件上传

9.1 文件上传

1)Spring MVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。
2)Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver
3)Spring MVC 上下文中默认没有装配 MultipartResovler,因此默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需现在上下文中配置 MultipartResolver

在这里插入图片描述

4)配置 MultipartResolver
defaultEncoding: 必须和用户 JSP 的 pageEncoding 属性一致,以便正确解析表单的内容,为了让 CommonsMultipartResolver 正确工作,必须先将 Jakarta Commons FileUpload 及 Jakarta Commons io 的类包添加到类路径下。

在这里插入图片描述

9.2 文件上传示例

1)拷贝jar包

commons-fileupload-1.2.1.jar
commons-io-2.0.jar
严重: Servlet /SpringMVC_06_FileUpload threw load() exception
java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileItemFactory

2)配置文件上传解析器

<!-- 配置文件上传解析器
id必须是"multipartResolver",否则,会报错误:
java.lang.IllegalArgumentException: Expected MultipartHttpServletRequest: is a MultipartResolver configured?-->
<bean id="multipartResolver"class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<property name="maxUploadSize" value="1024000"></property>
</bean>

3)上传页面

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="testUpload" method="post" enctype="multipart/form-data">
文件: <input type="file" name="file"/><br><br>
描述: <input type="text" name="desc"/><br><br>
<input type="submit" value="提交"/>
</form>
</body>
</html>

4)控制器方法

package com.atguigu.springmvc.crud.handlers;import java.io.IOException;
import java.io.InputStream;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;@Controller
public class UploadHandler {@RequestMapping(value="/testUpload",method=RequestMethod.POST)
public String testUpload(@RequestParam(value="desc",required=false) String desc, @RequestParam("file") MultipartFile multipartFile) throws IOException{                
System.out.println("desc : "+desc);
System.out.println("OriginalFilename : "+multipartFile.getOriginalFilename());
InputStream inputStream = multipartFile.getInputStream();
System.out.println("inputStream.available() : "+inputStream.available());
System.out.println("inputStream : "+inputStream);return "success"; //增加成功页面: /views/success.jsp
}
}

9.3 思考多个文件上传?

在这里插入图片描述

第10章 拦截器

10.1 自定义拦截器概述

1)Spring MVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器可以实现HandlerInterceptor接口,或者可以继承HandlerInterceptorAdapter 适配器类
preHandle():这个方法在业务处理器处理请求之前被调用,在该方法中对用户请求 request 进行处理。如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去进行处理,则返回true;如果程序员决定不需要再调用其他的组件去处理请求,则返回false。
postHandle():这个方法在业务处理器处理完请求后,但是DispatcherServlet 向客户端返回响应前被调用,在该方法中对用户请求request进行处理。
afterCompletion():这个方法在 DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。

10.2 实验代码(单个拦截器)

1)自定义拦截器类

package com.atguigu.springmvc.interceptors;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class FirstHandlerInterceptor implements HandlerInterceptor {@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
} 
}

2)配置拦截器

<mvc:interceptors>
<!-- 声明自定义拦截器 -->
<bean id="firstHandlerInterceptor"class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
</mvc:interceptors>

3)断点调试拦截器执行流程

在这里插入图片描述

4)拦截器方法执行顺序(小总结)

在这里插入图片描述

10.3 实验代码(多个拦截器)

1)自定义拦截器类(两个)

package com.atguigu.springmvc.interceptors;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class FirstHandlerInterceptor implements HandlerInterceptor {@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
}}	
package com.atguigu.springmvc.interceptors;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class SecondHandlerInterceptor implements HandlerInterceptor {@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println(this.getClass().getName() + " - afterCompletion");
}@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2, ModelAndView arg3) throws Exception {
System.out.println(this.getClass().getName() + " - postHandle");
}@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object arg2) throws Exception {
System.out.println(this.getClass().getName() + " - preHandle");
return true;
}}

2)配置自定义拦截器

<mvc:interceptors>
<!-- 声明自定义拦截器 -->
<bean id="firstHandlerInterceptor"class="com.atguigu.springmvc.interceptors.FirstHandlerInterceptor"></bean>
<!-- 配置拦截器引用 -->
<mvc:interceptor>                        
<mvc:mapping path="/empList"/>
<!-- <mvc:exclude-mapping path="/empList"/> -->
<bean id="secondHandlerInterceptor"class="com.atguigu.springmvc.interceptors.SecondHandlerInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
两个都是返回true :
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
两个都是返回false:
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
true,false
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion
false,true 
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle

10.4 多个拦截方法的执行顺序

1)关于执行顺序

com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - preHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor – preHandle
************************************biz method*******************************
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - postHandle
com.atguigu.springmvc.interceptors.SecondHandlerInterceptor - afterCompletion
com.atguigu.springmvc.interceptors.FirstHandlerInterceptor - afterCompletion

2)执行顺序图解
在这里插入图片描述

3)从源代码的执行角度分析流程:
PreHandle从小往大迭代

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (getInterceptors() != null) {
for (int i = 0; i < getInterceptors().length; i++) {HandlerInterceptor interceptor = getInterceptors()[i];if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);return false;
}this.interceptorIndex = i;
}
}return true;
}

在这里插入图片描述
PostHandle从小往大迭代

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
if (getInterceptors() == null) {return;
}
for (int i = getInterceptors().length - 1; i >= 0; i--) {HandlerInterceptor interceptor = getInterceptors()[i];interceptor.postHandle(request, response, this.handler, mv);
}
}

在这里插入图片描述

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception {if (getInterceptors() == null) {
return;
}
for (int i = this.interceptorIndex; i >= 0; i--) {HandlerInterceptor interceptor = getInterceptors()[i];try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}

在这里插入图片描述

在这里插入图片描述

4)源码分析:分析interceptorIndex的值情况

在这里插入图片描述
preHandle postHandle afterCompletion执行策略

package com.atguigu.springmvc.interceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;/*** 自定义拦截器*/
//@Component
public class MyFirstInterceptor implements HandlerInterceptor {/*** 1. 是在DispatcherServlet的939行   在请求处理方法之前执行*/public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {System.out.println("MyFirstInterceptor  preHandle");return true;}/*** 2. 在DispatcherServlet 959行   请求处理方法之后,视图处理之前执行。*/public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView) throws Exception {System.out.println("MyFirstInterceptor postHandle");}/*** 3. * 	 [1].在DispatcherServlet的 1030行   视图处理之后执行.(转发/重定向后执行)* 	 [2].当某个拦截器的preHandle返回false后,也会执行当前拦截器之前拦截器的afterCompletion*   [3].当DispatcherServlet的doDispath方法抛出异常,也可能会执行拦截器的afterComletion*/public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {System.out.println("MyFirstInterceptor afterCompletion");}}

第11章 运行流程图解

11.1 流程图

在这里插入图片描述

11.2 Spring工作流程描述

1)用户向服务器发送请求,请求被SpringMVC 前端控制器 DispatcherServlet捕获;
2)DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI):
判断请求URI对应的映射

①不存在:

再判断是否配置了mvc:default-servlet-handler:
如果没配置,则控制台报映射查找不到,客户端展示404错误
如果有配置,则执行目标资源(一般为静态资源,如:JS,CSS,HTML)

②存在:
执行下面流程
3)根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
4)DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。
5)如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法【正向】
6)提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)方法,处理请求。在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
①HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
②数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
③数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
④数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
7)Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
8)此时将开始执行拦截器的postHandle(…)方法【逆向】
9)根据返回的ModelAndView(此时会判断是否存在异常:如果存在异常,则执行HandlerExceptionResolver进行异常处理)选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet,根据Model和View,来渲染视图
10)在返回给客户端时需要执行拦截器的AfterCompletion方法【逆向】
11)将渲染结果返回给客户端

11.3 源码解析

11.3.1 搭建环境

1)拷贝jar包

spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
spring-web-4.0.0.RELEASE.jar
spring-webmvc-4.0.0.RELEASE.jar

2)配置文件web.xml

<servlet>
<servlet-name>springDispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

3)配置文件springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/><!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean></beans>

11.3.2 完成HelloWorld

1)页面链接

<a href="helloworld">Hello World</a>

2)控制器方法

package com.atguigu.springmvc.handler;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class HelloWorldHandler { 
@RequestMapping("/helloworld")
public String testHello(){ 
System.out.println("Hello,SpringMVC..."); 
return "success";
} 
}

3)成功页面:

/views/success.jsp

11.3.3 Debug实验

1)正常流程,运行出结果

2)没有配置<mvc:default-servlet-handler/>,测试,直接报404
①http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2
四月 20, 2016 11:53:19 上午 org.springframework.web.servlet.PageNotFound noHandlerFound
警告: No mapping found for HTTP request with URI [/SpringMVC_09_WorkFlow/helloworld2] in DispatcherServlet with name 'springDispatcherServlet'
②http://localhost:8080/SpringMVC_09_WorkFlow/test.html
四月 20, 2016 11:54:16 上午 org.springframework.web.servlet.PageNotFound noHandlerFound
警告: No mapping found for HTTP request with URI [/SpringMVC_09_WorkFlow/test.html] in DispatcherServlet with name 'springDispatcherServlet'
3)配置<mvc:default-servlet-handler/>,测试,会去查找目标资源
4)测试,依然发生错误,这时,需要配置:<mvc:annotation-driven/>,否则,映射解析不好使。

在这里插入图片描述

11.3.4 Debug流程分析

1)HandlerExecutionChain mappedHandler;包含了拦截器和处理器方法;
DispatcherServlet L902 916

org.springframework.web.servlet.HandlerExecutionChain
Handler execution chain, consisting of handler object and any handler interceptors. Returned byHandlerMapping's HandlerMapping.getHandler method.

在这里插入图片描述

2)HandlerMapping

org.springframework.web.servlet.HandlerMapping
Interface to be implemented by objects that define a mapping between requests and handler objects. 
This class can be implemented by application developers, although this is not necessary, as org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping and org.springframework.web.servlet.handler.SimpleUrlHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. 
HandlerMapping implementations can support mapped interceptors but do not have to. A handler will always be wrapped in a HandlerExecutionChain instance, optionally accompanied by some HandlerInterceptor instances. The DispatcherServlet will first call each HandlerInterceptor's preHandle method in the given order, finally invoking the handler itself if all preHandle methods have returned true. 
The ability to parameterize this mapping is a powerful and unusual capability of this MVC framework. For example, it is possible to write a custom mapping based on session state, cookie state or many other variables. No other MVC framework seems to be equally flexible. 
Note: Implementations can implement the org.springframework.core.Ordered interface to be able to specify a sorting order and thus a priority for getting applied by DispatcherServlet. Non-Ordered instances get treated as lowest priority.
3)没有配置<mvc:default-servlet-handler/>,<mvc:annotation-driven/>,发送一个不存在资源的请求路径,mappedHandler为null
http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2

在这里插入图片描述

在这里插入图片描述

4)配置<mvc:default-servlet-handler/>,<mvc:annotation-driven/>,发送一个不存在资源的请求路径
http://localhost:8080/SpringMVC_09_WorkFlow/helloworld2
mappedHandler不为null,原因是当循环simpleUrlHandlerMapping时,当做静态资源处理

在这里插入图片描述

11.3.5 断点

断点

第12章 Spring整合SpringMVC

通常情况下, 类似于数据源, 事务, 整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中).
实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao. 不需要都放在 SpringMVC的配置文件中. 也可以分多个 Spring 的配置文件, 然后使用 import 节点导入其他的配置文件

12.1 Spring 与SpringMVC的整合问题:

1)需要进行 Spring 整合 SpringMVC 吗 ?
2)还是否需要再加入 Spring 的 IOC 容器 ?
3)是否需要在web.xml 文件中配置启动 Spring IOC 容器的 ContextLoaderListener ?

需要: 通常情况下, 类似于数据源, 事务, 整合其他框架都是放在 Spring 的配置文件中(而不是放在 SpringMVC 的配置文件中).
实际上放入 Spring 配置文件对应的 IOC 容器中的还有 Service 和 Dao.
不需要: 都放在 SpringMVC 的配置文件中. 也可以分多个 Spring 的配置文件, 然后使
用 import 节点导入其他的配置文件
4)如何启动Spring IOC容器?
非WEB环境:直接在main方法或者是junit测试方法中通过new操作来创建.
WEB 环境: 我们希望SpringIOC容器在WEB应用服务器启动时就被创建.
通过监听器来监听ServletContext对象的创建, 监听到ServletContext对象被创建,就创建SpringIOC容器。
并且将容器对象绑定到ServletContext中, 让所有的web组件能共享到IOC容器对象.

12.2 Spring整合SpringMVC_解决方案配置监听器

1)监听器配置

<!-- 配置启动 Spring IOC 容器的 Listener -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

2)创建Spring的bean的配置文件:beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/><!-- 配置数据源, 整合其他框架, 事务等. --></beans>

3)springmvc配置文件:springmvc.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"><!-- 设置扫描组件的包 -->
<context:component-scan base-package="com.atguigu.springmvc"/> 
<!-- 配置视图解析器 -->
<bean id="internalResourceViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean><mvc:default-servlet-handler/> 
<mvc:annotation-driven/> 
</beans>

在HelloWorldHandler、UserService类中增加构造方法,启动服务器,查看构造器执行情况。
问题: 若 Spring 的 IOC 容器和 SpringMVC 的 IOC 容器扫描的包有重合的部分, 就会导致有的 bean 会被创建 2 次.
解决:
使 Spring 的 IOC 容器扫描的包和 SpringMVC 的 IOC 容器扫描的包没有重合的部分.
使用 exclude-filter 和 include-filter 子节点来规定只能扫描的注解
spring.xml中指定扫描,applicationContext.xml中配置排除扫描
Spring用来管理Dao和Service(Dao注入到Service),SpringMVC用来管理Handler,Handler调用Service

springmvc.xml
<context:component-scan base-package="com.atguigu.springmvc" use-default-filters="false">
<context:include-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
<context:include-filter type="annotation"expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
beans.xml
<context:component-scan base-package="com.atguigu.springmvc">
<context:exclude-filter type="annotation"expression="org.springframework.stereotype.Controller"/>
<context:exclude-filter type="annotation"expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
</context:component-scan>
<!-- 配置数据源, 整合其他框架, 事务等. -->

12.3 SpringIOC 容器和 SpringMVC IOC 容器的关系

SpringMVC 的 IOC 容器中的 bean 可以来引用 Spring IOC 容器中的 bean.
返回来呢 ? 反之则不行. Spring IOC 容器中的 bean 却不能来引用 SpringMVC IOC 容器中的 bean
1)在 Spring MVC 配置文件中引用业务层的 Bean
2)多个 Spring IOC 容器之间可以设置为父子关系,以实现良好的解耦。
3)Spring MVC WEB 层容器可作为 “业务层” Spring 容器的子容器:
即 WEB 层容器可以引用业务层容器的 Bean,而业务层容器却访问不到 WEB 层容器的 Bean

IOC容器 和 MVC容器 是 父子关系,子可以调用父,而不能反过来调用
在这里插入图片描述

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. 一个网站,让你拥有各类资源!!

    今天给你们介绍一个名叫合集网的资源网站,上面不仅有软件、应用的合集,还有很多在线资源,这么说吧,根据我对大家的了解,你只管打开这个网站,就会忍不住「卧槽,这也太丰富了吧」! 网址:https://www.heji.ltd/ 这个合集网主要分为首页、好站推荐、软件 App 和影视下载资…...

    2024/4/22 23:37:31
  2. Android 教你一步步搭建MVP+Retrofit+RxJava网络请求框架

    目录1.什么是MVP?2.什么是Retrofit?3.RxJava4.实践之前公司的项目用到了MVP+Retrofit+RxJava的框架进行网络请求,所以今天特此写一篇文章以做总结。相信很多人都听说过MVP、Retrofit、以及RxJava,有的人已经开始用了,有的人可能还不知道这是什么,以及到底怎么用。不过没关…...

    2024/4/21 12:25:06
  3. AFML读书笔记--Backtest Statistics & Understanding Strategy Risk

    Advance Finance Machine Learning读书笔记 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。 因为年初疫情影响,书剩在别的地方无法出门取,AFML所以断更了很久,现在持续更新中…… 之前有搜到大神weixin_38753422的AFML系列。…...

    2024/4/19 21:15:32
  4. wbrtc ICE连接-候选地址和选择

    完整SIP/SDP媒体协商概论-ICE初始offer发送详解2020-05-25 14:16:56 作者:james.zhu 来源:Asterisk开源派 评论:0  点击:5973在前面的章节中,我们主要讨论了ICE概览,介绍了ICE的基本处理流程和候选地址配对的算法概论和轻量级ICE部署(Lite Implementations)的讨…...

    2024/4/23 9:30:03
  5. VMware Workstation 14安装过程

    VMware Workstation 14安装过程 1.下载(可前往官网下载,也可私信博主获取) 2.双击下载好的安装文件进入安装,操作过程如下可根据需要修改安装位置这里我取消勾选了用户体验设置中的选项根据个人需要选择就可安装完成后,点击桌面图标打开效果本次分享就到这里了,感谢你能看…...

    2024/4/30 23:52:28
  6. 搭建react项目并配置路由

    一条龙服务: 1、全局安装create-react-app npm install -g create-react-app2、创建项目,安装依赖 create-react-app my-react-app3、进入项目 cd my-react-app4、启动项目 npm start项目启动,只有一个页面,下面开始安装路由,创建属于自己的结构 打开项目,在src下,创建几…...

    2024/5/4 4:52:48
  7. 力扣解题思路:队列与栈

    232. 用栈实现队列 思路:由于队列是先进先出,栈是先进后出,所以要用栈实现队列只能使用两个栈,因为执行一次出栈和入栈之后栈元素的顺序就会正好相反,所以再取出的peek就是队头啦~~ class MyQueue {private Stack<Integer> in = new Stack<>();private Stack&…...

    2024/5/4 1:28:28
  8. 腾讯云三大自研数据库之一 TBase 开源后首次重磅升级,复杂查询性能最高提升十倍

    7月13日,腾讯云自研分布式HTAP数据库TBase正式发布最新开源版本。这款被欧洲航天局作为“ Gaia Mission”行星探索项目的核心数据库,迎来了自开源以来的重磅升级。该版本在多活分布式能力、性能、安全性、可维护性等多个关键领域得到全面的增强和升级,复杂查询的性能提升十倍…...

    2024/5/4 4:09:34
  9. ftp上传工具 免安装,3款最好用的ftp上传工具 免安装

    ftp上传工具是能够免安装的你知道吗,你有特别喜欢的ftp上传工具吗,如果你对这方面不懂的话,但是现在又急着用这款的情况下,你刷到了我这篇文章,那么恭喜你,你已经成功了一半了。今天网就来给大家介绍一款不需要安装就能够使用的ftp上传工具吧。看完你绝对受益匪浅。 第一…...

    2024/4/28 1:38:28
  10. python matplotlib 绘制布林带

    python matplotlib 绘制布林带 csv文件下载地址: 链接: https://pan.baidu.com/s/1Jm4Z8wlskkloGYeeVNkOXg 提取码: p25v """绘制布林带 """import numpy as np import datetime as dt import matplotlib.pyplot as mp import matplotlib.dates …...

    2024/5/2 3:23:46
  11. CentOS 7.x学习笔记(三)虚拟软件(VM)的配置和使用

    CentOS 7.x学习笔记(三)虚拟软件(VM)的配置和使用 虚拟软件(VM)的网络模式 1. NAT网络模式 特点:所有对虚拟主机的访问都必须通过宿主机,虚拟主机和宿主机的网段可以不一致 优点:不容易出现局域网中IP冲突 缺点:其他宿主机不能直接访问虚拟主机2. 桥接网络模式 特点:…...

    2024/4/22 22:05:52
  12. 免费数据源

    Julie Joyce发文列出了 20 种被广泛认可的免费数据源,其中信息涵盖天文地理、政法医经等,比较全面。不过数据源中的大部分数据集都采集的美国信息,也有少部分是关于其他国家或全球的,你尽可从中筛选自己需要的数据集。Google Dataset Searchhttps://datasetsearch.research…...

    2024/5/4 2:35:38
  13. 知瓜数据|淘宝直播:成为新经济时代的引路人

    比尔盖茨曾说,“人们总是会高估未来一年的变化,却又往往低估未来十年的变革。” 从科技到商业,从生活到工作,这一点在人类社会的方方面面都得到了反复验证。这其实是在提醒我们,要留意那些看似细微却日积月累的变化,同时保持足够的耐心,随着时间流逝,它们终将汇成滔滔大…...

    2024/4/15 22:39:07
  14. 接口测试的流程

    接口测试的流程 大体流程: 1、(阅读)测试接口文档检验接口文档的完整性、正确性、一致性、易理解性和易浏览性。这个一般在实际测试过程中,都会弱化测试,不注重。2、编写测试用例这个大家都熟,根据接口文档编写测试用例。用例编写方法可以按照黑盒测试的用例编写规则来编…...

    2024/4/9 19:48:24
  15. Python:小练习

    练习题是从网上搜集来的,部分题目提供了多种解答5行代码 在2000-3200中,找到所有可以被7整除,但不是5的倍数的整数 for i in range(2000,3201):if i % 7 == 0 and i % 5 != 0:print(i)打印出所有的水仙花数,153=1^3+5^3+3^3 for i in range(100,1000):j = str(i)if (int(j[…...

    2024/5/4 5:50:18
  16. ui设计app设计风格有哪些?ui设计app界面设计流程是什么?

    ui设计app设计风格有哪些?对于一个初期设计师来说,这个问题确实显得有些困难,毕竟我们学习的过程中还没有真正面临过要自己去设计一个代表自己的产品。那么对于ui设计app设计风格有哪些?我自己总结了一些工作中的经验。ui设计app设计风格有哪些? APPUI界面设计布局风格一、…...

    2024/4/27 0:46:07
  17. 火影专场:Redis分布式锁实战

    火影专场:Redis分布式锁实战 我们学习 Java 都知道锁的概念,例如基于 JVM 实现的同步锁 synchronized,以及 jdk 提供的一套代码级别的锁机制 lock,我们在并发编程中会经常用这两种锁去保证代码在多线程环境下运行的正确性。但是这些锁机制在分布式场景下是不适用的,原因是在…...

    2024/5/3 17:25:04
  18. ubuntu安装python3.8 - 两种方式

    一种源码安装 参考文章:https://blog.csdn.net/lixuhui2468/article/details/105210957一种是add-apt-repository方式安装sudo apt-get install software-properties-common -y sudo add-apt-repository ppa:deadsnakes/ppa sudo apt-get update sudo apt-get install python3…...

    2024/4/9 19:46:08
  19. 牛客暑假多校 200713C Cover the Tree dfs序+思维

    链接:https://ac.nowcoder.com/acm/contest/5667/C 来源:牛客网 题意 给你一棵树 让你找出最小数量的“链”(链就是树上任意两点连线)使得覆盖所有边。 思路 dfs序 从左到右存遍历到的叶子节点 然后 从第一个和中间开始遍历 若最后剩下一个 和之前的任意一个叶子相连即可…...

    2024/4/22 19:15:05
  20. Error:(5, 55) java: 程序包org.springframework.cloud.netflix.eureka.server不存在

    Error:(5, 55) java: 程序包org.springframework.cloud.netflix.eureka.server不存在 今天,准备去网上找一个项目写写,没想到刚把项目搭建好跑一下看看,结果出现了java程序包找不到的错误,首先我先进行clean和install都没有问题,错误依旧,接着我把下载在maven中的删除加上重启i…...

    2024/5/1 2:30:51

最新文章

  1. 政安晨:【Keras机器学习示例演绎】(三十二)—— 在 Vision Transformers 中学习标记化

    目录 导言 导入 超参数 加载并准备 CIFAR-10 数据集 数据扩增 位置嵌入模块 变压器的 MLP 模块 令牌学习器模块 变换器组 带有 TokenLearner 模块的 ViT 模型 培训实用程序 使用 TokenLearner 培训和评估 ViT 实验结果 参数数量 最终说明 政安晨的个人主页&…...

    2024/5/4 9:56:11
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. OpenHarmony实战:Combo解决方案之ASR芯片移植案例

    本方案基于 OpenHarmony LiteOS-M 内核&#xff0c;使用 ASR582X 芯片的 DEV.WIFI.A 开发板进行开发移植。作为典型的 IOT Combo&#xff08;Wi-FiBLE&#xff09;解决方案&#xff0c;本文章介绍 ASR582X 的适配过程。 编译移植 目录规划 本方案的目录结构使用 Board 和 So…...

    2024/5/1 13:53:04
  4. AI如何影响装饰器模式与组合模式的选择与应用

    ​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 &#x1f680; 转载自热榜文章&#xff1a;设计模式深度解析&#xff1a;AI如何影响…...

    2024/5/1 11:09:14
  5. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/3 11:50:27
  6. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/2 16:04:58
  7. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/2 23:55:17
  8. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/3 16:00:51
  9. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/3 11:10:49
  10. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/3 21:22:01
  11. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/3 23:17:01
  12. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/2 23:47:43
  13. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/3 13:26:06
  14. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/3 1:55:15
  15. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/4 2:14:16
  16. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/3 16:23:03
  17. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/3 1:55:09
  18. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/2 8:37:00
  19. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/3 14:57:24
  20. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/2 9:47:25
  21. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/4 2:00:16
  22. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/3 22:03:11
  23. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/4 9:07:39
  24. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/3 1:54:59
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57