springMVC基础
一、SpringMVC概述
SpringMVC 是一种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级 Web 框架,属于 SpringFrameWork 的后续产品,已经融合在 Spring Web Flow 中。
SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优 秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时 它还支持 RESTful 编程风格的请求。
MVC(Model View Controller):是模型(model)-视图(view)-控制器(controller)的缩写,是一种用于设计创建 Web 应用程序表现层的模式。MVC 中每个部分各司其职。
1.1 组件介绍和执行流程
组件名称 | 概述 |
---|---|
DispatcherServlet | 作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合 性,提高每个组件的扩展性。 |
HandlerMapping | 通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式 等。 |
HandlAdapter | 通过扩展处理器适配器,支持更多类型的处理器,调用处理器传递参数等工作! |
ViewResolver | 通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。 |
View | SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最 常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程 序员根据业务需求开发具体的页面 |
执行流程:
① 用户发送请求至前端控制器DispatcherServlet。
② DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③ 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果 有则生成)一并返回给DispatcherServlet。
④ DispatcherServlet调用HandlerAdapter处理器适配器。
⑤ HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
⑥ Controller执行完成返回ModelAndView。
⑦ HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
⑧ DispatcherServlet将ModelAndView传给ViewReslover视图解析器。(进行判断,如果ModelAndVIew不为null就进行)
⑨ ViewReslover解析后返回具体View。
⑩ DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。DispatcherServlet响应用户。
1.3 快速开发步骤
① 导入SpringMVC相关坐标
② 配置SpringMVC核心控制器DispathcerServlet
③ 创建Controller类和视图页面
④ 使用注解配置Controller类中业务方法的映射地址
⑤ 配置SpringMVC核心文件 spring-mvc.xml
1.3.1 导入SpringMVC相关坐标
<!--Spring坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--SpringMVC坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--Servlet坐标-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided<scope> <!--设置只在编译和测试时候生效,发布后tomcat中有此类依赖避免冲突-->
</dependency>
1.3.2 初始化springMVC环境(spring环境),设定springmvc加载对应的bean
- 设置注解扫描
@Configuration
@ComponentScan("com.sys.controller")
public class SpringMvcConfig{}
1.3.2 初始化Servlet容器,配置核心控制器DispathcerServlet
- 创建配置类,继承AbsractDispatcherServletInitializer类
- 重写其中三个方法
public class ServletContainerInitConfig extends AbstractDispatcherServletinitializer {
//创建springMVC容器
protected WebApplicationContext createServletApplicationContext(){
//ApplicationContext ctx = new AnnotationConfigApplicationContext();
//加载配置文件,创建Springmvc容器
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置那些请求交给springMvc处理
protected String[] getServletMappings{
return new String["/"];
}
//创建spring容器
protected WebApplicationContext createRootApplicationContext(){
return null;
}
- 使用web.xml配置DispathcerServlet
<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:spring-mvc.xml</param-value>
</init-param>
<!--
<load-on-startup>1</load-on-startup>的作用
1)load-on-startup元素标记容器是否在启动的时候就加载这个servlet(实例化并调用其init()方法)。
2)它的值必须是一个整数,表示servlet应该被载入的顺序
3)当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
4)当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。
5)正数的值越小,该servlet的优先级越高,应用启动时就越先加载。
6)当值相同时,容器就会自己选择顺序来加载。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- 使用web.xml配置DispathcerServlet的核心配置文件spring-mvc.xml配置
<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="com.itheima"/>
</beans>
1.3.2 创建Controller类和视图页面
- 交给spring管理
- 定义处理请求具体方法
- 设置当前方法访问路径
- 设置返回路径
@Controller
public class UserCOntroller {
@RequestMapping("/")
@ResponseBody
public String save() {
return "";
}
}
二、请求参数处理
2.1 @RequestMapping注解
名称:@RequestMapping
类型:方法注解 类注解 (作用在类上:第一级的访问目录,作用在方法上:第二级的访问目录)
位置:SpirngMCV控制器方法定义
作用:设置当前方法请求访问路径,建立请求URL和处理方法之间的对应关系
属性:
①:path和value:这2个是一样的,都是指定访问路径,可以传入多个路径的数组格式
②:method:指定该方法的请求方式
③:params:指定限制请求参数的条件
④:headers:发送的请求中必须包含的请求头
举例:
@Controller(value="indexController")
@RequestMapping(value="user")
public class IndexController {
//注解路径
@RequestMapping(path = "/indexPage",params = {"name=Tom","password"},method = {RequestMethod.GET,RequestMethod.POST},headers = {"accept"})
public String indexPage(){
System.out.println("请求访问");
return "success";
}
}
①:@RequestMapping作用在方法上就是一级路径/user @RequestMapping作用在方法上就是二级路径;前两者合起来就是/user/indexPage
②:params指定了name必须是Tom和一个password,所以我们的uri路径就变成./user/indexPage?name=Tom&password=123
③:但是还指定了method必须以get/post两个请求访问,而且还得携带请求头accept
2.2 @RequestParam注解和请求参数绑定
名称:@RequestParam
类型:形参注解
位置:SpirngMCV控制器方法形参前面
作用:绑定请求参数与处理器方法形参之间的关系
属性:
①:name和value:这2个一样,映射表单信息,严格区分大小写
②:required:默认true,true代表必须获取此属性,false可有可无
举例:
@RequestMapping("/")
@ResponseBody
public String commonParamDifferntName(@RequestParam("name")String userName){}
//POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参可以接收参数
public String pojoParam(User user){}
//嵌套POJO参数:请求参数名与形参对象属性名相同,安装对象蹭吃结构关系即可接收嵌套POJO属性参数
//数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接受参数。
public String pojoParam(String[] likes){}
//List参数:请求参数名与形参对象名相同且请求参数为多个
public String listParam(@RequestParam List<String> likes){}
//Map参数:请求参数需要设置map的key值
public String mapParam(@RequestParam Map<STring,String> maps){}
嵌套POJO参数:对象中一个属性为对象,则请求参数为嵌套对象名.嵌套对象属性
数组参数和List参数:参数为likes,请求参数可以传入多个likes
Map参数:传入参数名为maps[key值]
2.3 @PathVariable注解
名称:@PathVariable
类型:形参注解
作用:来处理前台表单传递的数据不完整进行操作
属性:
①:value和name一样:表示占位符名称
②:required:表示是否必须包含
举例:
@RequestMapping(path = "/indexPrint/{id}")
public String indexPrint(@PathVariable(name = "id",required = true) int ID){
System.out.println("打印ID:"+ID);
return "success";
}
2.4 @RequestHeader和@CookieValue注解
两者都有name和value属性:获取指定数据;前者是获取请求头,后者是获取请求的Cookid某个值
举例:
@RequestMapping("/getHeaderAndCookie")
public String getHeaderAndCookie(@RequestHeader(name="accept") String accept,@CookieValue(name="JSESSIONID") String cookie){
System.out.println("Accept:"+accept);
System.out.println("JSESSIONID:"+cookie);
return "success";
}
2.5 @ModelAttribute注解
名称:@ModelAttribute
类型:形参注解 方法注解(作用在方法上:直接优先执行该方法)
位置:SpirngMCV控制器方法形参前面
作用:用于绑定url占位符
作用在方法上举例:
//保存的Controller方法 后执行
@RequestMapping(path = "/save")
public String save(User user) {
return "success";
}
//注解在方法上@ModelAttribute 优先执行
@ModelAttribute
public User holdFun(User user) {
return user;
}
会优先执行holdFun方法然后执行save方法
作用在参数上:作用在方法上和作用在参数上的唯一区别就是,前者有返回值后者不带返回值
//保存的Controller方法
@RequestMapping(path = "/save")
public String save(@ModelAttribute(value = "mapUser") User user) {
return "success";
}
//注解在方法上@ModelAttribute 优先执行
@ModelAttribute
public void holdFun(User user,Map<String,User> map) {
//因为没有返回值了,在方法参数上设置一个map,
map.put("mapUser",user);
}
注意:在使用@ModelAttribute的时候,一般用于前端form表单未封装的数据进行后期补充操作(说白了就是前端没有指定的输入框),如果前端指定了输入框,而且不输入值,这个到后端这个注解下是不可以操作的,如果前端传来地址为空(前端传往后端的数据都是空串如:“ ”),并且在后台设置值也是不生效的
就是前端输入了姓名和id但是没有地址,我用方法@ModelAttribute来设置补充默认地址和姓名,因为前端给了姓名所以方法中setName是不生效,只生效setAddress
2.6 @SessionAttribute注解
用于多次执行器方法间的参数共享,其中ModelMap是Model接口的实现类,这个类可以实现把数据存储到request域
@Controller(value = "indexController")
@RequestMapping(value = "/user")
@SessionAttributes(value = {"name"},types = String.class)//这里必须写model添加的数据
public class IndexController {
//添加session数据
@RequestMapping(path = "addAttribute")
public String addAttribute(Model model) {
model.addAttribute("name", "张三");
return "success";
}
//获取域session数据
@RequestMapping(path="getAttribute")
public String getAttribute(ModelMap model){
System.out.println(model.getAttribute("name"));
return "success";
}
//这里说明一下 要想删除Session里面的数据必须使用SessionStatus接口及实现类
@RequestMapping(path = "delAttribute")
public String delAttribute(SessionStatus status){
status.setComplete();
return "success";
}
}
2.7 日期类型参数处理
方法一:Date类型默认传入参数格式为yyyy/MM/dd,怎么更改默认为yyyy-MM-dd,这就得用SpringMVC给我们留的接口了Converter接口转换器
这里不多说了,可以了解一下。
方法二:利用springMVC辅助功能中@DateTimeFormat形参注解
1.在Mvc配置类中添加注解@EnableWebMvc
2.使用@dateTimeFormat
注解来配置Date格式
@RequestMapping("")
@ResponseBody
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd")Date date){}
Date类型默认传入参数格式为yyyy/MM/dd
2.8 文件类型参数处理
- 需要引入依赖包
<dependency>
<groupId>commons-fileupload</roupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
- 配置依赖包的第三方bean也就是multiparResolver解析器
//multipartResolver在第三方bean中定义了,必须为这个名
@Bean("multipartResolver")
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setMaxUploadSize(1024*1024);
return resolver;
}
//控制类接收文件类型为MultipartFile
public String fileParma(MultipartFile file){}
2.9 JSON类型处理
利用@RequestBody注解获取请求体
属性:
required:是否必须有请求体
默认true(必须包含)/false(可以没有请求体)
注:设置true就代表肯定是POST提交,设置false代表get/post提交都行
- 使用json类型需要导入相关依赖
<dependency>
<groupId>com.fasterxml.jackson.core</roupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
- 在Mvc配置类中添加注解
@EnableWebMvc
2.9.1 json数组
public String arrayParamForJson(@RequestBody List<String> list){}
//传入json格式
["sing","dance","rap"]
2.9.2 json对象(POJO)
public String pojoParamForJson(@RequestBody User user){}
//传入json格式
{
"name":"小红",
"age":"12",
"address":{
"province":"shanghai"
}
}
2.9.3 json数组(POJO)
public String pojoArrayParamForJson(@RequestBody List<User> list){}
//传入json格式
[
{
"name":"小红",
"age":"12",
"address":{
"province":"shanghai"
},{
"name":"小红",
"age":"12",
"address":{
"province":"shanghai"
}
]
三、Restful风格
RESTful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次。分别使用不同的请求代表不同的操作,如使用POST、DELETE、PUT、GET,使用不同方法对资源进行操作。分别对应添加、删除、修改、查询
3.1 传统风格资源描述方式
url中先定义动作,然后传递的参数表明这个动作操作的是哪个对象(数据)
先定位动作,然后定位对象
http://localhost:8080/springmvc02/user/queryUserById.action?id=1 查询
http://localhost:8080/springmvc02/user/saveUser.action 新增
http://localhost:8080/springmvc02/user/updateUser.action 更新
http://localhost:8080/springmvc02/user/deleteUserById.action?id=1 删除
3.2 RESTful风格资源描述方式
先定义对象
http://localhost:8080/springmvc02/user/1 (操作的对象) 查询,GET
http://localhost:8080/springmvc02/user 新增,POST
http://localhost:8080/springmvc02/user 更新,PUT
http://localhost:8080/springmvc02/user/1 删除,DELETE
3.3 涉及注解
- @RequestMapping 中的 method参数
- @
//@Controller
//@ResponseBody
@RestController //替代上面两个注解
@RequestMapping("")
Public class UserController{
//@RequestMapping(method = RequestMethod.POST,path = "/") //可以使用PostMapping替代
@PostMapping("/")
public String
}
四、解决中文乱码问题
出现乱码问题是因为前台和后端的编码不一致所导致的,tomcat在8版本的时候解决了GET请求乱码,而POST请求我们可以使用过滤器的方式对所有的请求拦截过滤放行,使之得到不是乱码的字符
4.1 GET请求中文乱码处理
设置访问路径编码字符集
<build>
<plugins>
<groupId>prg.apache.tomcat.maven</groupId>
<artifactId>tomact7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port> <!-- tocat端口号 -->
<path>/</path> <!-- 虚拟目录 -->
<uriEncoding>UTF-8</uriEncoding> <!-- 访问路径编码字符集 -->
</configuration>
</plugins>
</build>
4.2 POST请求中文乱码处理
方法一:在初始化Servlet容器,配置核心控制器DispathcerServlet中,继承的AbstractDispatcherServletinitializer类中,重写getServletFilters()方法
public class ServletContainerInitConfig extends AbstractDispatcherServletinitializer {
//设置参数编码为UTF-8
@Override
protected Filer[] getServletFilters(){
CharacterEncodingFilter characterEnocdingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
return new Filter[] {characterEncodingFilter};
}
}
方法二:在web.xml下面配置过滤器 解决中文乱码问题
<!--配置过滤器 解决中文乱码问题-->
<!--
public class CharacterEncodingFilter extends OncePerRequestFilter {
@Nullable
private String encoding;
private boolean forceRequestEncoding;
private boolean forceResponseEncoding;
查看CharacterEncodingFilter类发现有个encoding,这个就是具体的字符集是什么,我们要设置一下
/*:代表所有的请求我们都要拦截进行过滤字符集,任何放行
-->
<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>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>