目录
1.SpringMVC介绍
2.入门程序
(1)需求:
客户端点击超链接,发送请求,服务端执行相应的处理方法,方法执行成功后,转发到成功jsp页面
(2)入门环境搭建:
创建maven项目
解决maven项目创建过慢问题
补全maven的目录结构
在pom.xml中导入依赖
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.cqu</groupId>
<artifactId>springMVC_Demo01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<!-- 版本锁定 -->
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 集成tomcat7插件 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<uriEncoding>UTF-8</uriEncoding>
<port>8888</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
在web.xml中配置核心的前端控制器
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 核心的前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
在src/main/resources下新建一个spring的配置文件springmvc.xml
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
部署项目
因为我们在pom.xml中集成了tomcat7
所以我们可以直接使用maven集成的tomcat一键构建部署运行项目
(3)实现代码
在webapp目录下重新写一个index.jsp
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h3>入门程序</h3>
<a href="/hello">入门程序</a>
</body>
</html>
HelloController.java
package cn.cqu.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* 控制器类
* 接受请求
*/
//把这个类交给spring来管理
@Controller
public class HelloController {
//请求映射,/hello即为这个方法的请求路径
@RequestMapping(path="/hello")
public String sayHello(){
System.out.println("Hello springMVC");
return "success";//此处默认返回的是jsp的名字
}
}
springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="cn.cqu"/>
<!--视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--开启springMVC框架注解的支持-->
<mvc:annotation-driven/>
</beans>
web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!-- 核心的前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</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>
<!--启动服务器时
创建DispatcherServlet对象,
加载配置文件springmvc.xml,
然后扫描注解生效
然后控制器类会被扫到,就有了该类的对象
然后一发请求,该路径映射到的方法就能被执行了
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>入门成功</title>
</head>
<body>
<h3>入门成功</h3>
</body>
</html>
部署
访问
(4)上述代码的流程总结
(5)入门案例中涉及的组件
- (1)DispatcherServlet:前端控制器
用户请求到达前端控制器,它相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其他组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性
- (2)HandlerMapping:处理器映射器
HandlerMapping负责根据用户请求找到Handler即处理器,SpringMVC提供了不同的映射器实现不同的映射方式,例如,配置文件方式,实现接口方式,注解方式等
- (3)Handler:处理器
它就是我们开发中要编写的具体业务控制器,由DispatcherServlet把用户请求转发到Handler,由Handler对具体的用户请求进行处理
- (4)HandlerAdapter:处理器适配器
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
- (5)View Resolver:视图解析器
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户
- (6)View:视图
SpringMVC框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等,我们最常用的视图就是jsp
- (7)<mvc:annotation-driven>说明
- 在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
- 使 用 <mvc:annotation-driven> 自动加载 RequestMappingHandlerMapping (处理映射器)和 RequestMappingHandlerAdapter ( 处 理 适 配 器 )
- 可 用 在 SpringMVC.xml 配 置 文 件 中 使 用
- <mvc:annotation-driven>替代注解处理器和适配器的配置。
它就相当于在 xml 中配置了:
<!-- ================HandlerMapping=========== -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping"></bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- ===============HandlerAdapter===============-->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter"></bean>
<bean
class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<!-- ====================HadnlerExceptionResolvers=============== -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept
ionResolver"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv
er"></bean>
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"
></bean>
明确:
- 我们只需要编写处理具体业务的控制器以及视图。
(6)@RequestMapping
- 作用:
-
用于建立请求 URL 和处理请求方法之间的映射关系。即请求访问的注解中配置的URL路径,就会执行相应的方法
-
-
出现位置:可以出现在类上或方法上
-
类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。
-
它出现的目的是为了使我们的 URL 可以按照模块化管理:
-
例如:
-
账户模块:
-
/account/add
-
/account/update
-
/account/delete
...
-
订单模块:
-
/order/add
-
/order/update
-
/order/delete
-
- 红色的部分就是把 RequsetMappding 写在类上,使我们的 URL 更加精细。
-
- 方法上:
-
请求 URL 的第二级访问目录。
-
-
-
属性:
-
value或path:用于指定请求的 URL
-
method:用于指定请求的方式。
-
params:用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和配置的一模一样。
-
例如:
-
params = {"accountName"},表示请求参数必须有 accountName
-
params = {"money!=100"},表示请求参数中money不能是100
-
-
-
headers:用于指定限制请求头的条件
-
注意:以上四个属性只要出现2个或以上时,他们的关系是与的关系
-
3.请求参数的绑定
请求绑定:客户端发送来的请求中带着请求参数,而我们在控制器拿到参数的过程称作请求参数绑定
SpringMVC 绑定请求参数的过程是通过把表单提交请求参数,作为控制器中方法参数进行绑定的。
示例1:
<a href="account/findAccount?accountId=10">查询账户</a>
中请求参数是:
accountId=10
/**
* 查询账户
* @return
*/
@RequestMapping("/findAccount")
public String findAccount(Integer accountId) {
System.out.println("查询了账户。。。。"+accountId);
return "success";
}
注意:提交表单的name和接受方法中的参数的名称是相同的
(1)支持的各数据类型演示
- 基本类型参数:包括基本类型和 String 类型
- 此处参见上述示例1
- POJO 类型参数:包括实体类,以及关联的实体类
- param.jsp
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>请求参数绑定</title> </head> <body> <form action="param/saveAccount" method="post"> <%-- 以下input中的name必须与Account中的字段名称一样,因为会通过name去查找它对应的set方法 --%> 姓名:<input type="text" name="username"/><br> 密码:<input type="password" name="password"/><br> 金额:<input type="text" name="money"/><br> 用户的姓名:<input type="text" name="user.uname"/><br> 用户的年龄:<input type="text" name="user.age"/><br> <input type="submit" name="提交"/> </form> </body> </html>
- User.java
-
package cn.cqu.domain; import java.io.Serializable; public class User implements Serializable { private String uname; private Integer age; public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "User='" + uname + '\'' + ", age=" + age + '}'; } }
- Account.java
-
package cn.cqu.domain; import java.io.Serializable; public class Account implements Serializable { private String username; private String password; private Double money; private User user; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @Override public String toString() { return "Account{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", money=" + money + ", user=" + user + '}'; } }
- ParamController.java
-
package cn.cqu.controller; import cn.cqu.domain.Account; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * 请求参数绑定绑定把数据封装到JavaBean的类当中 */ @Controller @RequestMapping("/param") public class ParamController { @RequestMapping("/saveAccount") public String saveAccount(Account account) { System.out.println("执行了。。。"); System.out.println(account); return "success"; } }
- 数组和集合类型参数:包括 List 结构和 Map 结构的集合(包括数组)
- param.jsp
-
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>请求参数绑定</title> </head> <body> <%--把数据封装在Account类中,类中存在list和map的集合--%> <form action="param/saveAccount" method="post"> <%-- 以下input中的name必须与Account中的字段名称一样,因为会通过name去查找它对应的set方法 --%> 姓名:<input type="text" name="username"/><br> 密码:<input type="password" name="password"/><br> 金额:<input type="text" name="money"/><br> 用户1的姓名:<input type="text" name="list[0].uname"/><br> 用户1的年龄:<input type="text" name="list[0].age"/><br> 用户2的姓名:<input type="text" name="map['one'].uname"/><br> 用户2的年龄:<input type="text" name="map['one'].age"/><br> <input type="submit" name="提交"/> </form> </body> </html>
- User.java
-
package cn.cqu.domain; import java.io.Serializable; public class User implements Serializable { private String uname; private Integer age; public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "User='" + uname + '\'' + ", age=" + age + '}'; } }
- Account.java
-
package cn.cqu.domain; import java.io.Serializable; import java.util.List; import java.util.Map; public class Account implements Serializable { private String username; private String password; private Double money; private List<User> list; private Map<String,User> map; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Double getMoney() { return money; } public void setMoney(Double money) { this.money = money; } public List<User> getList() { return list; } public void setList(List<User> list) { this.list = list; } public Map<String, User> getMap() { return map; } public void setMap(Map<String, User> map) { this.map = map; } @Override public String toString() { return "Account{" + "username='" + username + '\'' + ", password='" + password + '\'' + ", money=" + money + ", list=" + list + ", map=" + map + '}'; } }
- ParamController.java
-
package cn.cqu.controller; import cn.cqu.domain.Account; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; /** * 请求参数绑定绑定把数据封装到JavaBean的类当中 */ @Controller @RequestMapping("/param") public class ParamController { @RequestMapping("/saveAccount") public String saveAccount(Account account) { System.out.println("执行了。。。"); System.out.println(account); return "success"; } }
SpringMVC 绑定请求参数是自动实现的,但是要想使用,必须遵循使用要求。
(2)请求参数乱码问题
1)post方式
-
配置中文乱码的过滤器:(在web.xml中配置)
在 springmvc 的配置文件中可以配置,静态资源不过滤:
- <!-- location 表示路径,mapping 表示文件,**表示该目录下的文件以及子目录的文件 -->
- <mvc:resources location="/css/" mapping="/css/**"/>
- <mvc:resources location="/images/" mapping="/images/**"/>
- <mvc:resources location="/scripts/" mapping="/javascript/**"/>
2)get方式
tomacat 对 GET 和 POST 请求处理方式是不同的,GET 请求的编码问题,要改 tomcat 的 server.xml
配置文件,如下:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
改为:
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" useBodyEncodingForURI="true"/>
如果遇到 ajax 请求仍然乱码,请把:
useBodyEncodingForURI="true"改为 URIEncoding="UTF-8"
即可。
4.自定义类型转换器
(1)SpringMVC中类型转换分析
页面提交的任何数据都是字符串类型,而在我们传给控制器中的方法时,接受时,不一定时字符串,如上述的Account中Integer,Double类型等等,其实这是因为SpringMVC框架内部自动帮我们进行了数据类型转换,基本上常用的类型它都会帮我们转,我们做开发时不用去管,但是当我们存在一些特殊的格式的时候,它没办法帮我们自动转,这时,我们需要手动去解决,即自定义类型转换器
示例:
这种格式的日期,SpringMVC不能自动进行类型转换,不能完成封装数据,报错
(2)自定义类型转换器
使用步骤:
第一步:定义一个类,实现 Converter 接口,该接口有两个泛型。
package cn.cqu.utils;
import org.springframework.core.convert.converter.Converter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 把字符串转换为日期
*/
public class StringtoDateConverter implements Converter<String, Date> {
@Override
public Date convert(String source) {
//判断
if(source == null)
{
throw new RuntimeException("请您传入数据");
}
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
//把字符串转换为日期
return df.parse(source);
} catch (ParseException e) {
throw new RuntimeException("数据类型转换出现错误");
}
}
}
第二步:在 spring 配置文件中配置类型转换器。(如我这里是上述的springmvc.xml)
第三步:在 annotation-driven 标签中引用配置的类型转换服务
再次部署运行:
5.获取Servlet原生的API
SpringMVC 还支持使用原始 ServletAPI 对象作为控制器方法的参数。支持原始 ServletAPI 对象有:
- HttpServletRequest
- HttpServletResponse
- HttpSession
- java.security.Principal
- Locale
- InputStream
- OutputStream
- Reader
- Writer
我们可以把上述对象,直接写在控制的方法参数中使用。
控制器中示例代码:
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {
System.out.println(request);
System.out.println(response);
System.out.println(session);
return "success"; }