一、入门
1、第一个SpringMVC程序
1.1框架搭建
-
基于框架的搭建,首先还是需要创建一个maven项目,其次导入依赖,此处我们搭建的是一个web项目,所以可以在搭建maven项目的时候就创建一个web项目,当然,最后再创建也是可以的,这里采用最后创建。
-
配置web.xml文件
<?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">
<!-- 注册前端控制器DispatcherServlet-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--这里的springMVC.xml要与类路径下面的spring 名字高度一致-->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 创建一个class类
public class TestController {
}
- 配置spring.xml文件
下面的thymeleaf是模板
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置扫描组件-->
<context:component-scan base-package="com.study.mvc.controller"/>
<!-- 配置Thymeleaf视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
- 通过配置的视图前缀,我们需要在/WEB-INF/templates/ 该路径下写html文件,在WEB-INF下新建一个templates文件夹,编写html代码。需要注意要使用thymeleaf,所以需要在html标签上配置 xmlns:th=“http://www.thymeleaf.org”
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>
- 编写class类
package com.study.mvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController {
@RequestMapping("/")
public String index() {
return "index";
}
}
1.2@RequestMapping注解
1.2.1@RequestMapping注解的功能
它的作用就是将请求和处理请求的控制器方法关联起来,建立一个映射关系,当springMVC接收到这个指定的请求,就会来找到在在映射关系关系中对应的控制器来处理这个请求。
1.2.2@RequestMapping注解的位置
@RequestMapping标识一个类:设置映射请求的请求路径的初始信息
@RequestMapping标识一个方法:设置映射请求请求路径的具体信息
通过查看@RequestMapping的源码可知,它出现在的位置在类和方法上,在类上设置设置属性,就是在请求的路径上再加上一个路径,用来区分不同控制器相同的方法名配置的属性。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {
String name() default "";
@AliasFor("path")
String[] value() default {};
@AliasFor("value")
String[] path() default {};
RequestMethod[] method() default {};
String[] params() default {};
String[] headers() default {};
String[] consumes() default {};
String[] produces() default {};
}
1.2.3@RequestMapping注解的value属性
此注解的value属性通过请求的请求地址匹配请求映射,它的value属性是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求,而且注解的value属性必须设置,至少通过请求地址匹配请求映射。
1.2.4@RequestMapping注解的Params属性
@RequestMapping注解的Params属性是通过请求参数匹配请求映射,他是一个字符串类型的数据组,通过四种表达式设置请求参数和请求映射的匹配关系:
param":要求请求映射所匹配的请求必须携带param请求参数
“!param”:要求请求映射所匹配的请求必须不能携带param请求参数
“param=value”:要求请求映射所匹配的请求必须携带param请求参数且param=value
“param!=value”:要求请求映射所匹配的请求必须携带param请求参数但是param!=value
1.2.5springMVC支持的Ant风格路径
这个风格的路径包括以下三个部分
//第一种用?占位,但是此风格不能包含/,/在路径下代表的是一个目录
@RequestMapping("/a?a/testAnt")
//第二种,用*,此方法代表的是多个字符,同样不能包含/
@RequestMapping("/a*a/testAnt")
//第三种,可以包含/,并且为多个,但是必须是在两个//间就是以下的格式
@RequestMapping("/**/testAnt")//只能是(xxx/**/xxx)
1.2.6路径中的占位符
这就是rest方式:/deleteUser/1,@RequestMapping注解的value属性中通过占位符{xxx}表示传输的数据,在通过@PathVariable注解,将占位符所表示的数据赋值给控制器方法的形参。
<a th:href="@{/hello/TestRest/lisi}">测试路径中的占位符</a>
@RequestMapping("/TestRest/{username}")
public String testRest(@PathVariable("username") String username) {
System.out.println(username);
return "success";
}
2、springMVC获取请求参数
2.1通过SevrvletAPI获取参数
<a th:href="@{/testServletAPI(username='zhangsan',password=123)}">请求参数测试Param</a>
@Controller
public class ParamController {
@RequestMapping("/testServletAPI")
public String testServletAPI(HttpServletRequest request) {
String username = request.getParameter("username");
int password = Integer.parseInt(request.getParameter("password"));
System.out.println("username :" +username+ "password:" + password);
return "success";
}
}
2.2通过控制器方法的形参获取请求参数
在控制器方法的形参位置,设置和请求参数同名的形参,当浏览器发送请求,匹配到请求映射时,在DispatcherServlet中就会将请求参数赋值给相应的形参
<form th:action="@{/testParam}" th:method="get">
账号:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
爱好:<input type="checkbox" name="hobby" value="跑步">跑步
<input type="checkbox" name="hobby" value="打球">打球
<input type="checkbox" name="hobby" value="体哦啊高">体哦啊高
<input type="submit" value="提交">
</form>
@RequestMapping("/testParam")
public String testParam(String username,Integer password,String hobby) {
System.out.println("username :" +username+ " password:" + password + "hobby" + hobby);
return "success";
}
这里需要注意的是,要保证前端的数据和控制器的数据保持一致否则会报400错误,比如上述的password参数类型是Integer,所以前端form表单填入的数据就得是Integer类型,否则在页面跳转中直接报400错误。其次我们的请求参数名和我们的形参名也必须一致,否则获取不到数据。
如果请求参数和形参名不一致,应该怎么解决呢?
我们看可以通过注解来解决
@RequestParam("user_name") String username
@RequestParam注解一共有三个属性:
value:指定为形参赋值的请求参数的参数名
required:设置是否必须传输此请求参数,默认值为true
若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter ‘xxx’ is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null
defaultValue:不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值
2.3解决获取请求参数的乱码问题
解决get请求乱码问题,只需要从TomCat入手,将tomcat中的service.xml配置文件中的以下配置中加上配置UTF-8. URIEncoding=“UTF-8”
<Connector port="8080" URIEncoding="UTF-8" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
而解决post乱码就需要看程序的执行顺序,在tomcat启动前解决,也就是程序运行前,就需要设置编码格式,所以直接配置过滤器来解决这个乱码的问题。
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
二、域对象共享数据
1、获取与对象共享数据的集中方式
1.1通过ServletAPI获取域中的对象
1、通过ServletAPI获取域中的对象
使用th标签拿到request域中的值,通过传入他的name来获取
<p th:text="${testRequestScorp}"></p>
@Controller
public class ScopeController {
@RequestMapping("/testRequestByServletAPI")
public String testByServletAPI(HttpServletRequest request) {
request.setAttribute("testRequestScorp","hello");
return "success";
}
}
1.2通过ModelView获取请求域中的对象
在这里需要注意必须设置视图名称,我们要返回的是视图,获取对象的方法也是一样的使用th标签进行获取
<p th:text="${testRequestScorp}"></p>
//使用ModelAndView获取请求域对象
@RequestMapping("/requestByModelAndView")
public ModelAndView modelAndView() {
ModelAndView mdv = new ModelAndView();
//向请求域共享对象
mdv.addObject("testRequestScorp1","hello,ModelView");
//设置视图名称
mdv.setViewName("success");
return mdv;
}
1.3使用Model向request域对象共享数据
@RequestMapping("/testModel")
public String testModel(Model model){
model.addAttribute("testScope", "hello,Model");
return "success";
}
1.4使用map向request域对象共享数据
@RequestMapping("/testMap")
public String testMap(Map<String, Object> map){
map.put("testScope", "hello,Map");
return "success";
}
1.5使用ModelMap向request域对象共享数据
@RequestMapping("/testModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testScope", "hello,ModelMap");
return "success";
}
2、Model、ModelMap、Map的关系
如下代码所示,我们先通过反射机制获取当前对象实现类的全类名
@RequestMapping("/testRequestModel")
public String model(Model model) {
model.addAttribute("testRequest","hello model");
System.out.println("model" + model.getClass().getName());
return "success";
}
@RequestMapping("/testRequestMap")
public String testMap(Map<String,Object> map) {
map.put("testRequest","hello map");
System.out.println(map.getClass().getName());
return "success";
}
@RequestMapping("/testRequestModelMap")
public String testModelMap(ModelMap modelMap){
modelMap.addAttribute("testRequest", "hello,ModelMap");
System.out.println(modelMap.getClass().getName());
return "success";
}
我们可以发现,我们通过反射机制获取当前对象实现类的全类名,发现这三个对象的实现类的全类名居然是完全一样的。
通过上述的一系列操作,我们不难发现,这三个对象存在一定的关系:Model、ModelMap、Map类型的参数其实本质上都是 BindingAwareModelMap 类型的
他们之间的继承关系如下:
public interface Model{}
public class ModelMap extends LinkedHashMap<String, Object> {}
public class ExtendedModelMap extends ModelMap implements Model {}
public class BindingAwareModelMap extends ExtendedModelMap {}
-
Model是一个接口,他是模型数据最顶层的接口
-
Map就是JDK中的Map,ModelMap 继承了 LinkedHashMap<String,Object>
-
LinkedHashMap又实现了Map接口!所以ModelMap是Map接口的实现类
-
BindingAwareModelMap继承于ExtendedModelMap。而ExtendedModelMap继承了ModelMap所以BingingAwareModel可以创建ModelMap,同时又实现了Model接口,也可以实例化Model