1、Spring MVC概述
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等等。
M model 模型层 DAO封装 >>> Mybatis
V view 视图层 html css js jsp
C controller 控制层 Servlet封装 >>> springMVC
SpringMVC是spring为展现层提供的基于MVC设计理念的优秀WEB框架,是目前最主流的MVC框架之一
SpringMVC通过一套注解,可以让普通的JAVA类成为contrllor控制器,无需继承Servlet,实现了控制层和Servlet之间的解耦
SpringMVC支持Rest风格的URL写法
SpringMVC采用了松耦合,可热插的主键结构,比其他的框架更具扩展性和灵活性
2、Spring MVC项目搭建
(1)修改web.xml 中的版本约束
可以创建一个javaEE项目,然后复制web.xml文件中的内容即可
并在web.xml中配置DispatcherServlet(前端控制器)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
</web-app>
<!--配置前端控制器(DispatcherServlet)-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数,指定SpringMVC配置文件的路径-->
<!--
当然,不使用init-param指定springMVC配置文件的路径,那么dispatcherServlet会自动到默认路径为/WEB-INF下找指定名字的配置文件
到一个默认路径下读取默认名称的.xml配置文件
默认配置文件名为:<servlet-name>-servlet.xml
我们暂时不推荐这种方式
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC.xml</param-value>
</init-param>
<!--启动立即初始化servlet-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!--配置DispatcherServlet的映射路径,匹配所有的资源,除了JSP-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
(2)导入jar依赖
<!--引用SpringMVC框架所需的依赖-->
<!--spring核心容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--springJDBC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring事务控制包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring orm 映射依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.5</version>
</dependency>
<!--Apache Commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--log4j2 日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--spring test测试支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.5</version>
<scope>test</scope>
</dependency>
<!--junit5单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!--springMVC支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<!--自己写servlet所需的两个依赖-->
<!--Servlet jsp 依赖 可选-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<!--编译的时候不用编译,只是在编码编写的时候使用-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
(3)加入SpringMVC的配置文件
在resources下添加 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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--扫描controller层-->
<context:component-scan base-package="com.wml"></context:component-scan>
<!--三大组件配置-->
<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!--配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--开启MVC注解驱动,自动给我们配置好处理器映射器适配器-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 指定路径的前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--配置静态资源放行-->
<!--mapping:url中的路径 location:对应路径到项目中那个目录中去找对应的资源-->
<!--<mvc:resources mapping="css/**" location="css/"></mvc:resources>
<mvc:resources mapping="js/**" location="js/"></mvc:resources>
<mvc:resources mapping="img/**" location="img/"></mvc:resources>-->
<mvc:resources mapping="static/**" location="static/"></mvc:resources>
</beans>
(4)添加log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--debug日志比较细 info粗略-->
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
(5)编写controller层处理器
/*@Component有三个子注解*/
/*
* @WebServlet只能给类上定义请求映射路径
* @RequestMapping既能给类上和方法上也能请求映射路径
* */
@Controller//实例化
public class MyController02 {
//定义一个处理请求的方法
/*
* 处理器
* 返回定义为String,用来表名要跳转的页面的路径
* */
@RequestMapping("/firstContrller.do") //请求什么路径能映射到下面的方法
public String firstController(HttpServletRequest req){
System.out.println("firstController");
/*return "first.jsp";*/
/*return "/first.jsp";*/
/*return "/WEB-INF/view/first.jsp";*/
return "first";
}
/* @RequestMapping("/secondContrller.do") //请求什么路径能映射到下面的方法
public String secondController(){
System.out.println("secondController");
return "first.jsp";
}*/
}
(6)编写视图层
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
this is first.jsp
</body>
</html>
启动测试
3、执行流程和三大组件
执行时序图:
执行原理图:
1 DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由 它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
2 HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的 映射方式,例如:配置文件方式,实现接口方式,注解方式等。
3 Handler:处理器 (自己定义的Controller处理单元)
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
4 HandlAdapter:处理器适配器
通过 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 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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--扫描controller层-->
<context:component-scan base-package="com.wml"></context:component-scan>
<!--三大组件配置-->
<!--配置处理器映射器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>
<!--配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定路径的前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
第二种方法使用注解方法配置
<?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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
">
<!--扫描controller层-->
<context:component-scan base-package="com.wml"></context:component-scan>
<!--开启MVC注解驱动,自动给我们配置好处理器映射器适配器-->
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定路径的前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
4、静态资源放行
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<link rel="stylesheet" type="text/css" href="static/css/aaa.css">
<script src="static/js/bbb.js"></script>
</head>
<body>
this is index1.jsp
<img src="static/img/8.jpeg">
</body>
</html>
<!--配置静态资源放行-->
<!--mapping:url中的路径 location:对应路径到项目中那个目录中去找对应的资源-->
<mvc:resources mapping="css/**" location="/css/"></mvc:resources>
<mvc:resources mapping="js/**" location="/js/"></mvc:resources>
<mvc:resources mapping="img/**" location="/img/"></mvc:resources>
或者可以直接建一个static文件夹放静态资源
<mvc:resources mapping="static/**" location="static/"></mvc:resources>
5、控制请求
控制请求参数和请求头
1 @RequestMapping控制请求方式
method属性可以控制请求的方式,值为RequestMethod的枚举值
准备Controller层代码
@Controller//实例化
public class MyController01 {
//定义一个处理请求的方法
/* "/testRequest"里面斜线加不加都行*/
@RequestMapping(value = "/testRequest",method = {RequestMethod.GET,RequestMethod.POST})
public String testRequest(){
System.out.println("testRequest");
return "success";
}
}
index2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="testRequest" method="get">
<input type="submit" value="提交">
</form>
</body>
</html>
2 @RequestMapping控制请求参数params和请求头headers
param:表示请求中必须包含名为param的参数
!param:表示请求中不能包含名为param的参数
param = value 表示请求中包含名为param的参数,但是值必须是value
param != value 表示请求中包含名为param的参数,但是值不能是value
{“param1”,“param2=value”},可以将对于多个参数的要求写入数组
准备Controller层代码
@Controller//实例化
/*@RequestMapping("/wml")*/
public class MyController01 {
/*控制请求参数params*/
@RequestMapping(value = "/testRequest2",params = {"username","password"})
public String testRequest2(){
System.out.println("testRequest2");
return "success";
}
/*控制请求头headers*/
@RequestMapping(value = "/testRequest3",headers = "Accept-Encoding!=gzip,deflate")
public String testRequest3(){
System.out.println("testRequest3");
return "success";
}
}
index2.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="testRequest2" method="get">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="测试params">
</form>
<br/>
<form action="testRequest3" method="get">
<input type="text" name="username">
<input type="text" name="password">
<input type="submit" value="测试params">
</form>
<br/>
</body>
</html>
3 @PathVariable注解和RESTful风格的支持
普通形式的url
*****/contextPath/aaa.do
*****/contextPath/aaa.jsp
*****/contextPath/aaa.html
*****/contextPath/css/aaa.css
*****/contextPath/js/aaa.js
*****/contextPath/aaa.do?id=10&username=root
restFul风格的url
*****/contextPath/aaa/10/root
*****/contextPath/aaa
controller 处理单元
@Controller
public class PathController02 {
@RequestMapping("/testPathVariable/{id}/{username}")
public String testPathVariable(@PathVariable(value = "id") String id, @PathVariable("username") String username){
System.out.println("id:"+id);
System.out.println("username:" + username);
System.out.println("testPathVariable");
/*return "WEB-INF/view/success.jsp";*/
return "success";//配置视图解析器去掉前缀和后缀
}
}
Http协议中,四个表示操作方式的动词"GET POST PUT DELETE",他们对应四种基本操作,GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源
简单的说,就是我们在访问资源时,可以通过这四个状态来表示对于资源的不同操作,这四个状态表现为我们请求的四种方式
/controller/1 HTTP GET :得到id为1 的资源
/controller/1 HTTP DELETE :删除id为1的资源
/controller/1 HTTP PUT :更新id为1 的资源
/controller/1 HTTP POST :增加id为1 的资源
在访问同一个url的时候,通过不同的请求方式,对应到不同的controller处理单元
转换原理:
准备Controller层代码
@RestController
public class TestRestful {
@RequestMapping(value = "testRest/{id}",method= RequestMethod.GET)
public String testGet(@PathVariable("id") String id){
System.out.println("testGet:"+id);
return "success";
}
@RequestMapping(value = "testRest/{id}",method= RequestMethod.POST)
public String testPost(@PathVariable("id") String id){
System.out.println("testPost:"+id);
return "success";
}
/*下面两种需要配置过滤器hiddenHttpMethodFilter*/
@RequestMapping(value = "testRest/{id}",method= RequestMethod.PUT)
public String testPUT(@PathVariable("id") String id){
System.out.println("testPUT:"+id);
return "success";
}
@RequestMapping(value = "testRest/{id}",method= RequestMethod.DELETE)
public String testDELETE(@PathVariable("id") String id){
System.out.println("testDELETE:"+id);
return "success";
}
}
web.xml
<!--配置hiddenHttpMethodFilter ,将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>
准备页面代码testPage.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="testRest/10/" method="get">
<input type="submit" value="GET">
</form>
<br/>
<form action="testRest/10/" method="post">
<input type="submit" value="post">
</form>
<br/>
<%--请求中携带一个特殊的参数 _method 用该参数表述PUT DELETE--%>
<form action="testRest/10/" method="post">
<input type="hidden" name="_method" value="PUT">
<input type="submit" value="PUT">
</form>
<br/>
<form action="testRest/10/" method="post">
<input type="hidden" name="_method" value="DELETE">
<input type="submit" value="DELETE">
</form>
</body>
</html>
6、参数的注入
1、参数注入
Controller层
@RestController
public class testDataController01 {
/*紧耦合方式参数注入
* 使用传统的HttpServletRequest对象获取参数 javax.servlet
* */
@RequestMapping("/getParamByRequest.do")
public String getParam1(HttpServletRequest req, HttpServletResponse resp){
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println("username:"+username+"password:"+password);
return "getParamSuccess";
}
/*解耦合方式参数注入
* HttpServletRequest对象获取参数 通过SpringMVC框架功能,自动转换参数
* 处理单元参数列表中参数名必须和请求中的参数名一致
* 如不一致,可以通过@RequestParma注解进行转换
* */
@RequestMapping("/getParamByArgName.do")
public String getParam2(String username,@RequestParam("pwd")int password) {
System.out.println("username:" + username + "password:" + password);
return "getParamSuccess";
}
}
DataPage.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="getParamByRequest.do">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="byRequest">
</form>
<hr/>
<form action="getParamByArgName.do">
<input type="text" name="username">
<input type="password" name="pwd">
<input type="submit" value="byRequest">
</form>
</body>
</html>
2、注入POJOS(实体类)类型参数
Controller层
ReceiveDataController
@RestController
public class ReceiveDataController {
/*
* 使用Pojo就收参数时,注意事项:
* 提交的参数名必须和Pojo的属性名保持一致
* springMVC底层通过反射给参数列表的属性赋值
* 通过set方法设置属性值得,不是直接通过操作属性
* POJO的属性一定要有set方法,要不然就会接受失败
* */
@RequestMapping("/getDataByPojo01")
public String getDataByPojo01(String pname,String page,String gender,String[] hobby,String birthdate){
System.out.println(pname);
System.out.println(page);
System.out.println(gender);
System.out.println(Arrays.toString(hobby));
System.out.println(birthdate);
return"success";
}
@RequestMapping("/getDataByPojo02")
public String getDataByPojo02(person p){
System.out.println(p);
return"success";
}
}
Pojo层
person
@AllArgsConstructor
@NoArgsConstructor
@Data
public class person implements Serializable {
private String pname;
private String page;
private String gender;
private String[] hobby;
private String birthdate;
}
resources
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--debug日志比较细 info粗略-->
<Configuration status="DEBUG">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" />
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console" />
</Root>
</Loggers>
</Configuration>
SpringMVC
<?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:tx="http://www.springframework.org/schema/tx"
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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--扫描controller层-->
<context:component-scan base-package="com.wml"></context:component-scan>
<mvc:annotation-driven/>
<!--配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定路径的前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
Webapp
PojoIndex.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--
radio:单选框
checkbox:复选框
--%>
<form action="getDataByPojo01">
<p>姓名:<input type="text" name="pname"></p>
<p>年龄:<input type="text" name="page"></p>
<p>性别:
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
</p>
<p>爱好:
<input type="checkbox" name="hobby" value="1">篮球
<input type="checkbox" name="hobby" value="2">足球
<input type="checkbox" name="hobby" value="3">羽毛球
<input type="checkbox" name="hobby" value="4">乒乓球
</p>
<p>生日:
<input type="text" name="birthdate">
</p>
<input type="submit">
</form>
<hr/>
<form action="getDataByPojo02">
<p>姓名:<input type="text" name="pname"></p>
<p>年龄:<input type="text" name="page"></p>
<p>性别:
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
</p>
<p>爱好:
<input type="checkbox" name="hobby" value="1">篮球
<input type="checkbox" name="hobby" value="2">足球
<input type="checkbox" name="hobby" value="3">羽毛球
<input type="checkbox" name="hobby" value="4">乒乓球
</p>
<p>生日:
<input type="text" name="birthdate">
</p>
<input type="submit">
</form>
</body>
</html>
导入jar依赖
<dependencies>
<!--引用SpringMVC框架所需的依赖-->
<!--spring核心容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--springJDBC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring事务控制包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring orm 映射依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.5</version>
</dependency>
<!--Apache Commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--log4j2 日志-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
<scope>test</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--spring test测试支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.5</version>
<scope>test</scope>
</dependency>
<!--junit5单元测试-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<!--springMVC支持包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.5</version>
</dependency>
<!--自己写servlet所需的两个依赖-->
<!--Servlet jsp 依赖 可选-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<!--编译的时候不用编译,只是在编码编写的时候使用-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
3、注入DATA(日期)类型参数
日期转化:
第一种方式:注解方式(掌握):
@DateTimeFormat(pattern = “yyyy-MM-dd”) 可以用于方法参数列表和 类的属性上
@RequestMapping("/getDataByPojo03")
public String getDataByPojo03(@DateTimeFormat(pattern = "yyyy-MM-dd")Date birthdate){
System.out.println(birthdate);
return"success";
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class person implements Serializable {
private String pname;
private String page;
private String gender;
private String[] hobby;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthdate;
}
第二种方式: 配置转换器(麻烦了解):
第一步定义转换器
public class StringToDateConverter implements Converter<String, Date> {
private SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd");
@Override
public Date convert(String s) {
Date date = null;
try {
date = dateFormat.parse(s);
} catch (ParseException e) {
throw new RuntimeException("日期转换异常");
}
return date;
}
}
第二步,springmvc.xml 中配置转换器
<!--数据转换工厂-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<!--配置类型转化器-->
<property name="converters">
<array>
<!--注入自定义转换器对象-->
<bean class="com.wml.util.StringToDateConverter"></bean>
</array>
</property>
</bean>
<!--这里配置转换服务工厂-->
<mvc:annotation-driven conversion-service="conversionService"/>
4、注入LIST集合类型参数
实体类:
@AllArgsConstructor
@NoArgsConstructor
@Data
public class person implements Serializable {
private String pname;
private String page;
private String gender;
private String[] hobby;
//@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthdate;
private Pet pet;
private List<Pet> pets;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Pet implements Serializable {
private String petName;
private String petType;
}
Controller:
@RestController
public class ReceiveDataController {
@RequestMapping("/getDataByPojo04")
public String getDataByPojo04(person p){
System.out.println(p);
System.out.println(p.getPets());
return"success";
}
}
form表单:
<form action="getDataByPojo04">
<p>姓名:<input type="text" name="pname"></p>
<p>年龄:<input type="text" name="page"></p>
<p>性别:
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
</p>
<p>爱好:
<input type="checkbox" name="hobby" value="1">篮球
<input type="checkbox" name="hobby" value="2">足球
<input type="checkbox" name="hobby" value="3">羽毛球
<input type="checkbox" name="hobby" value="4">乒乓球
</p>
<p>生日:
<input type="text" name="birthdate">
</p>
单个宠物:
<p>
宠物1:名字:<input type="text" name="pet.petName">
类型:<input type="text" name="pet.petType">
</p>
宠物List:
<p>
宠物1:名字:<input type="text" name="pets[0].petName">
类型:<input type="text" name="pets[0].petType">
</p>
<p>
宠物2:名字:<input type="text" name="pets[1].petName">
类型:<input type="text" name="pets[1].petType">
</p>
<input type="submit">
</form>
5、注入MAP集合类型参数
实体类:
@AllArgsConstructor
@NoArgsConstructor
@Data
public class person implements Serializable {
private String pname;
private String page;
private String gender;
private String[] hobby;
//@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthdate;
private Pet pet;
private List<Pet> pets;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Pet implements Serializable {
private String petName;
private String petType;
}
Controller:
@RestController
public class ReceiveDataController {
@RequestMapping("/getDataByPojo04")
public String getDataByPojo04(person p){
System.out.println(p);
System.out.println(p.getPets());
return"success";
}
}
form表单:
实体类:
```java
@AllArgsConstructor
@NoArgsConstructor
@Data
public class person implements Serializable {
private String pname;
private String page;
private String gender;
private String[] hobby;
//@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthdate;
private Pet pet;
private List<Pet> pets;
private Map<String,Pet>petMap;
}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Pet implements Serializable {
private String petName;
private String petType;
}
Controller:
@RestController
public class ReceiveDataController {
@RequestMapping("/getDataByPojo04")
public String getDataByPojo04(person p){
System.out.println(p);
System.out.println(p.getPets());
return"success";
}
}
form表单:
<form action="getDataByPojo04">
<p>姓名:<input type="text" name="pname"></p>
<p>年龄:<input type="text" name="page"></p>
<p>性别:
<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="2">女
</p>
<p>爱好:
<input type="checkbox" name="hobby" value="1">篮球
<input type="checkbox" name="hobby" value="2">足球
<input type="checkbox" name="hobby" value="3">羽毛球
<input type="checkbox" name="hobby" value="4">乒乓球
</p>
<p>生日:
<input type="text" name="birthdate">
</p>
单个宠物:
<p>
宠物1:名字:<input type="text" name="pet.petName">
类型:<input type="text" name="pet.petType">
</p>
宠物List:
<p>
宠物1:名字:<input type="text" name="pets[0].petName">
类型:<input type="text" name="pets[0].petType">
</p>
<p>
宠物2:名字:<input type="text" name="pets[1].petName">
类型:<input type="text" name="pets[1].petType">
</p>
<input type="submit">
</form>
==6、请求参数乱码问题==
GET乱码问题
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210520094033409.png#pic_center)
web.xml中配置编码过滤器
```xml
<filter>
<filter-name>encFilter</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>
</filter>
<filter-mapping>
<filter-name>encFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
7、常见注解
1、@RequestMapping
作用:
用于建立请求 URL 和处理请求方法之间的对应关系
出现位置:
类上: 请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头
方法上: 请求 URL 的第二级访问目录
属性:
value:用于指定请求的 URL。它和 path 属性的作用是一样的。
method:用于指定请求的方式。
params(了解):用于指定限制请求参数的条件。它支持简单的表达式。要求请求参数的 key 和 value 必须和 配置的一模一样。
headers(了解):用于指定限制请求消息头的条件。
2 @RequestParam
作用:
把请求中指定名称的参数给控制器中的形参赋值。
属性:
value:请求参数中的名称。
required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@RequestMapping("/getRequestParam")
public String getRequestParam(@RequestParam("name")String uname, @RequestParam(value="age",required=false)Integer age){
System.out.println(username+","+age);
return "success";
}
3、@PathVariable
Restful的简介 :
REST(英文:Representational State Transfer,简称 REST)restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
restful 的优点
它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。
作用:
用于绑定 url 中的占位符。例如:请求 url 中 /delete/{id},这个{id}就是 url 占位符。 url 支持占位符是 spring3.0 之后加入的。是 springmvc 支持 rest 风格 URL 的一个重要标志。
属性:
value:用于指定 url 中占位符名称。
required:是否必须提供占位符。
@Controller
public class PathController {
@RequestMapping("/testPathVariable/{id}/{username}")
public String testPathVariable(@PathVariable("id") Integer id, @PathVariable("username") String username){
System.out.println("id:"+id);
System.out.println("username:"+username);
System.out.println("testPathVariable1");
return "success";
}
}
4、@RequestHeader(了解)
作用:
用于获取请求消息头。
属性:
value:提供消息头名称
required:是否必须有此消息头
@RequestMapping("/getRequestHeader")
public String getRequestHeader(@RequestHeader(value="Accept", required=false)String requestHeader){
System.out.println(requestHeader);
return "success";
}
5、@CookieValue(了解)
作用:
用于把指定 cookie 名称的值传入控制器方法参数。
属性:
value:指定 cookie 的名称。
required:是否必须有此 cookie
实现
@RequestMapping("/getCookie")
public String getCookie(@CookieValue(value="JSESSIONID",required=false) String cookieValue){
System.out.println(cookieValue);
return "success";
}
8、void响应
@Controller
public class testRespnose {
/*
* 1、
*单元方法返回值为void
* */
@RequestMapping("/testVoid")
public void testVoid(){
System.out.println("void controller");
}
/*
* 2、
* 紧耦合方式
* 转发和重定向ServletAPI 实现
* */
@RequestMapping("Dome1")
public void testDemo1(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//请求转发
/*request.getRequestDispatcher("/forwardPage.jsp").forward(request,response);*/
//响应重定向
response.sendRedirect(request.getContextPath()+"/redirectPage.jsp");
}
/*
*3、
* 松耦合方式
*使用forward关键字完成响应
*使用redirect关键字完成响应
* */
@RequestMapping("Dome2")
public String testDemo2(){
//请求转发
/*
* 返回字符串告诉DispatcherServlet跳转的路径
* 在路径之前放上一个forward:关键字,就是请求转发
* 如果路径前的关键字是forward,那么可以省略不写
* */
//return "forward:/forwardPage.jsp";
return "/forwardPage.jsp";
}
@RequestMapping("Dome3")
public String testDemo3(){
//响应重定向
/*
* 返回字符串告诉DispatcherServlet跳转的路径
* 在路径之前放上一个redirect:关键字,就是响应重定向
* 如果路径前的关键字是redirect,那么不可以省略不写
* /表示当前项目下,这里不需要项目的上下文路径
* */
return "redirect:/redirectPage.jsp";
}
//4、使用View视图转发和重定向*/
@RequestMapping("Dome4")
public View testDemo4(HttpServletRequest req){
//请求转发
/*RedirectView中所做的操作,最终的实现是在renderMergedOutputModel中完成实现的,简单来说RedirectView实现了链接的重定向,并且将数据保存到FlashMap中,这样在跳转后的链接中可以获取一些数据.*/
View view = null;
//view = new InternalResourceView("/forwardPage.jsp");
//响应重定向
//view = new RedirectView(req.getContextPath()+"forwardPage.jsp");
return view;
}
/*5、使用ModelAndView转发重定向*/
@RequestMapping("Dome5")
public ModelAndView testDemo5(HttpServletRequest req){
ModelAndView mv =new ModelAndView();
//请求转发
/*
ModelAndView中的Model代表模型,View代表视图,这个名字就很好地解释了该类的作用。业务处理器调用模型层处理完用户请求后,把结果数据存储在该类的model属性中,把要返回的视图信息存储在该类的view属性中,然后让该ModelAndView返回该Spring MVC框架。
* */
//mv.setViewName("forward:/forwardPage.jsp");
//mv.setView(new InternalResourceView("/forwardPage.jsp"));
//响应重定向
mv.setViewName("redirect:/redirectPage.jsp");
//mv.setView (new RedirectView(req.getContextPath()+"forwardPage.jsp"));
return mv;
}
/*
* 6、
* ResponseBody 响应 json 数据
* */
}
ResponseBody 响应 json 数据
当浏览器发起一个ajax请求给服务器,服务器调用对应的单元方法处理ajax请求。而ajax的请求在被处理完成后,其处理结果需要直接响应。而目前我们在单元方 法中响应ajax请求,使用的是response对象,需要我们自己将要响应的数据转换 为json字符串响应,比较麻烦,而我们一直希望在单元方法中无论是否是ajax请求,都使用return语句来完成资源的响应,怎么办?
既然我们希望使用单元方法的返回值来响应ajax请求的处理结果,而目前DispatcherServlet的底层会将单元方法的返回值按照请求转发或者重定向来处理,所以就需要我们告诉DispatcherServlet,单元方法的返回值不要按照请求转发或者重定向处理,而是按照直接响应处理,将单元方法的返回值直接响应给浏览器。
第一步 导入jackson的jar
<!--json依赖-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
第二步 声明单元方法处理ajax请求,并在单元方法上新增注解@ResponseBody
/*
* @ResponseBody
* 1方法的返回值不在作为界面跳转依据,而已直接作为返回的数据
* 2将方法的返回的数据自动使用ObjectMapper转换为JSON
*/
@ResponseBody
@RequestMapping("testAjax")
public Pet testAjax(Person p) throws JsonProcessingException {
System.out.println(p);
Pet pet =new Pet("Tom","cat");
return pet;
}
测试代码:
public class TestJson {
@Test
public void testAjax() throws Exception {
Pet pet = new Pet("Tom","Cat");
ObjectMapper om = new ObjectMapper();
String asString = om.writeValueAsString(pet);
System.out.println(asString);
}
}
注意:把我们要响应的数据直接return即可,返回值类型为要return的数据类型。
第三步: 在ajax的回调函数中,无需再次使用eval函数将响应数据转换为json对象直接使用即可。
在js中复制文件夹jquery.min.js
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="static/js/jquery.min.js"></script>
<script>
$(function(){
$("#btn").click(function(){
$.get("testAjax",{pname:"小花",page:19},function (data) {
console.log(data)/*打印*/
})
})
})
</script>
</head>
<body>
<input id="btn" type="button" value="testJSON">
</body>
</html>
关于 @RestController
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面