一、SpringMVC简介
1.什么是MVC
Model:数据模型
View:视图
Controller:控制器
MVC是一种Web应用架构,是一种代码设计思想
思想:将所有客户端请求交由控制器,由控制器将其进行分发,并将结果响应给客户端。
2.常见MVC框架
使用原生Servlet实现MVC:
- 配置比较复杂
- 数据处理太麻烦
实际开发中一般都会使用MVC框架,如Struts1、Struts2、SpringMVC等
对比:
- 效率方面,Struts1>SpringMVC>Struts2
Struts2是多例的,效率低
Struts1和SpringMVC是单例的,两者效率差不多。 - 配置方面:SpringMVC>Struts2>Struts1
3.为什么使用SpringMVC
- 使用注解来替代xml配置,更简单
- 是单例的,效率高
- 用户可以自定义,扩展性好
- SpringMVC和Spring无缝衔接
二、SpringMVC实现原理
1.流程图
springMVC运行原理
2.执行过程
- DispatcherServlet
SpringMVC核心控制器(前端控制器):主要是用来分发请求的 - HandlerMapping
映射处理器:根据请求的url来映射查找到对应的Handler
Handler就是Controller层的实现类 - HandlerAdapter
适配器:用来适配不同的处理器Handler
处理器有两种实现方式:实现接口、基于注解,所以执行前需要先适配 - Handler
处理器:真正用来处理和执行业务,并产生数据模型Model和视图View,
Handler会将Model和View封装成ModelAndView对象并返回。 - ViewResolver
视图解析器:根据视图名称解析成具体的视图,一般多为jsp页面,然后把它封装成View对象并返回。 - View
视图:使用具体的视图技术进行渲染,结合Model进行数据展示。
视图有很多种形式:jsp、freemarker、velocity、excel、pdf等。
三、第一个SpringMVC程序
1.添加jar包
<!--SpringMVC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
2.配置核心控制器
<!--配置DispatcherServlet-->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--在web应用启动时执行-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3.创建配置文件
两种定义方式:
- 使用默认的位置,默认在WEB-INF/目录下,
名称为:核心Servlet名称-servlet.xml
例如:springMVC-servlet.xml
- 自定义位置,名称自定义
根据Controller实现方式的不同,配置方式也有所不同,有两种方式定义Controller
- 实现接口
- 基于注解
3.1实现接口的Controller
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//获取请求信息
String name = req.getParameter("name");
ModelAndView mav = new ModelAndView();
//在ModelAndView中添加属性
mav.addObject("msg","Hello "+name);
//指定视图路径
mav.setViewName("hello");
//返回
return mav;
}
}
springMVC-servlet.xml
<!--2.配置HandlerMapping-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--3.配置HandlerAdapter-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--
4.配置Handler
name:访问控制器的url
class:指定控制器的全限定路径
-->
<bean name="/hello" class="controller.HelloController"/>
<!--5.配置ViewResolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--指定前缀-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--指定后缀-->
<property name="suffix" value=".jsp"/>
<!--6.配置view,使用jsp视图技术渲染页面-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
3.2 基于注解的Controller
@Controller
public class HelloAnnotationController {
@RequestMapping("/hello")
public ModelAndView sayHello(String name){
ModelAndView mav = new ModelAndView();
mav.addObject("msg","你好 "+name);
mav.setViewName("hello");
return mav;
}
}
springmvc.xml
<!--2.配置映射处理器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!--3.配置处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<!--4.指定Handler-->
<context:component-scan base-package="controller"/>
<!--5.配置视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--配置指定前缀和后缀-->
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
<!--6.配置视图 如果使用的时jsp视图技术,可以省略不写-->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
注意:也可以使用<mvc:annotation-driven/>
来省略映射处理器和映射适配器。
四、静态资源的放行
当DispatcherServlet的<url-pattern>/</url-pattern>
配置为/时,会拦截所有请求,其中包括静态资源。
问题:因为DispatcherServlet会将静态资源当作Controller,所以会拿到HandlerMapping中去查找。
解决1:
- 使用Tomcat提供的默认Servlet
tomcat提供了默认的Servlet来处理静态资源
<!--使用Tomcat提供的默认Servlet处理静态资源-->
<mvc:default-servlet-handler/>
缺点:
- 如果使用的不是Tomcat,有可能不生效
- 只能读取webapp下的资源,无法读取WEB-INF下的资源
解决2:
- 在SpringMVC配置文件中添加
<mvc:resources mapping="/img/**" location="/WEB-INF/img/"/>
2.直接访问jsp页面
问题:默认不能直接访问WEB-INF下的jsp页面,一般都是在Controller中做转发的映射
解决:在SpringMVC配置文件中添加如下语句
<!--直接访问jsp页面,view-name代表想要访问的视图名-->
<mvc:view-controller path="/userLogin" view-name="login"/>
五、Controller详解
1.方法的返回值,共有四种类型:
- ModelAndView:表示返回的是数据模型和视图名
- String:表示返回的是视图的名字
三种写法(形式):
普通字符串-->表示视图名称
"forward:"+url-->转发
"redirect:"+url-->重定向 - void:将请求的url作为视图名称,很少使用
- Object:表示返回的是数据模型(一般返回的是json数据)
2.SpringMVC注解
SpringMVC常用注解
3.@RequestMapping
3.1 基本用法
该注解可以定义在方法上,也可以定义在类上,用来表示层级关系。
配置URL时以/开头和不以/开头的区别:
添加/代表从项目的根目录开始访问,不添加/代表从当前位置开始查找。
3.2 URL的多种写法
请求映射路径有三种写法:
- Ant风格
*:表示单层目录,可以匹配任意字符 ,但是只能在一个层级中
**:表示多层或单层目录,可以没有字符,“/”也可以没有
?:表示单个字符,必须有一个字符 - Rest风格
{变量}:表示url中的占位符,可以结合@PathVariable获取值
{变量:正则}:表示使用正则表达式来限定值的格式 - 固定写法
value和path互为别名,值为数组,可以指定多个值
3.3 根据请求方式来访问
限定请求方式:GET、POST、PUT、DELETE等
/**
* 根据请求方式访问
*/
@RequestMapping(value = "/test6",method = RequestMethod.GET)
public String test6(){
return "hello";
}
// @RequestMapping(path = "/user/{id}",method = RequestMethod.GET)
@GetMapping("/user/{id}")
public String deleteUser(@PathVariable Integer id){
System.out.println("delete user id:"+id);
return "hello";
}
// @RequestMapping(path = "/user/{id}",method = RequestMethod.POST)
@PostMapping("/user/{id}")
public String selectUser(@PathVariable Integer id){
System.out.println("select user id:"+id);
return "hello";
}
3.4 其他属性
- params
限定请求参数,必须符合指定条件
//请求参数中必须包含id,uname必须为admin,pwd不能是123
@RequestMapping(path = "/test7",params = {"id","uname=admin","pwd!=123"})
public String test7(){
return "hello";
}
- headers
限定请求头,必须符合指定条件才能访问url
//请求头中必须包含Cookie
@RequestMapping(path = "/test8",headers = {"Cookie"})
public String test8(){
return "hello";
}
六、方法的参数
1.JavaEE组件
- HttpServletRequest
- HttpServletResponse
- HttpSession
- IO流
- InputStream/OutputStream
- Reader/Writer
- 向界面传递数据
Model、Map、ModelMap
将数据存储到request作用域中
4.String和基本数据类型
- @RequestParam:
表示参数值来源于同名请求参数,默认所有参数都添加该注解。
但是如果手动添加了注解,就必须为参数传值。
如果不传参数值可以在注解中使用required属性,将值改为false。
也可以添加defaultValue属性,为参数添加默认值。 - @PathVariable
表示参数来源于url - @RequestHeader
表示参数来源于请求头 - @CookieValue
表示参数来源于Cookie - @RequestBody
表示参数来源于请求体(只有POST请求才有请求体)
5.自定义类型
@ModelAttribute:
将请求数据转化为对象
条件:对象的属性名必须与表单元素一致
@ModelAttribute注解的两种用法
- 在方法参数前面添加该注解
作用:将请求参数转换为对象 - 在方法上面添加该注解
作用:在调用所有目标方法前都会调用添加@ModelAttribute注解的方法,并向模型中添加数据
6.错误参数
- Errors、BindingResult
用来获取错误信息,实现服务端的数据校验
实际开发中,既要做客户端表单校验,又要做服务端表单校验
7、服务器校验框架
1.简介
1.1 JSR303校验
JSR303是一个数据验证的标准规范,用于对JavaBean中的属性进行校验,称为Bean Validation。
提供了常用的校验的注解
1.2 Hibernate Validator
是JSR303的一个参考实现,并提供了扩展注解
2.用法
2.1 添加jar包
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator-annotation-processor</artifactId>
<version>${hibernate-validator-annotation-processor.version}</version>
</dependency>
2.2 为参数对象添加注解
在需要校验的对象前面添加@Valid
注解
2.3 为对象中的属性添加注解
示例:
@NotEmpty(message = "用户名不能为空")
@Pattern(regexp = "\\w(6,10)",message = "用户名只能包含数字,字母,下划线,且长度为6~10位")
private String uname;
@Length(min = 6,max = 16,message = "密码长度必须为6~16位")
private String pwd;
@Pattern(regexp = "(139|133|131)\\d{8}",message = "手机号格式不正确")
private String phone;
@Email(message = "邮箱格式不正确")
private String email;
@Range(min = 1,max = 120,message = "年龄必须在1~120之间")
private int age;
8、类型转换
1.简介
数据绑定流程:获取值--->查找转换器--->转换--->后台数据校验--->数据绑定
两种解决方式:
- 方式1:使用PropertyEditor
- 方式2:使用Converter(推荐)
2.使用PropertyEditor
步骤:
- 定义属性编辑器
- 注册属性编辑器
@InitBinder
缺点:
- 代码是嵌套在Controller层中
- 只能从字符串转换成相应的对象
3.使用Converter
步骤:
- 定义转换器,实现Converter接口。
- 配置自定义转换器
<!-- 配置自定义转换器 -->
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<!--将自定义的转换器添加到set集合中-->
<bean class="converter.StringToAddressConverter"/>
<bean class="converter.AddressToStringConverter"/>
</set>
</property>
</bean>
- 加载自定义转换器
<mvc:annotation-driven conversion-service="conversionService"/>
9.@SessionAttributes
作用:将模型中指定名称的数据存储到session中
10.统一异常处理
1.简介
对异常进行统一处理
两种方式:
- 使用web技术提供的统一异常处理
- 使用SpringMVC提供的异常处理
2.使用web技术的异常处理
<!--404异常-->
<error-page>
<error-code>404</error-code>
<location>/404.jsp</location>
</error-page>
<!--500异常-->
<error-page>
<error-code>500</error-code>
<location>/500.jsp</location>
</error-page>
3.使用SpringMVC的异常处理
步骤:
1.定义一个异常处理类(通知),添加@ControllerAdvice注解
2.定义异常方法并添加@ExceptionHandler注解
@ControllerAdvice
public class ExceptionAdvice {
@ExceptionHandler(ArithmeticException.class)
public String arithmetic(Exception e){
System.out.println(e);
System.out.println("警报!程序出现算数异常"+e.getMessage());
return "error/arithmetic";
}
@ExceptionHandler(NullPointerException.class)
public String nullPointer(Exception e){
System.out.println(e);
System.out.println("警报!程序出现空指针异常"+e.getMessage());
return "error/nullPointer";
}
@ExceptionHandler(Exception.class)
public String exception(Exception e){
System.out.println(e);
System.out.println("警报!程序出现异常"+e.getMessage());
return "error/exception";
}
}
11.拦截器
1.简介
使用Interceptor对请求进行拦截,类似于过滤器Filter
2.用法
步骤:
1.定于一个类,InterceptorHandler
2.实现接口中的方法
3.配置拦截器
<!--注册拦截器-->
<mvc:interceptors>
<!--拦截所有请求-->
<bean class="interceptor.HelloInterceptor"/>
<!--拦截指定请求-->
<mvc:interceptor>
<mvc:mapping path="/user/regist"/>
<mvc:mapping path="/login"/>
<bean class="interceptor.RegistInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
12.处理AJAX
1.@ResponseBody
为方法添加该注解中,会将返回值写到响应体中
2.返回JSON
三种方式:
- jackson:SpringMVC默认支持
- gson:SpringMVC默认支持,google开发
- fastjson:SpringMVC默认不支持,alibaba开发
2.1 使用jackson
步骤:
1.添加jar包
<!--处理json-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-databind.version}</version>
</dependency>
2.配置消息转换器(可省略)
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
2.2 使用gson
步骤:
1.添加jar包
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
</dependency>
2.配置消息转换器(可省略)
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器-->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.GsonHttpMessageConverter"/>
</mvc:message-converters>
</mvc:annotation-driven>
2.3 使用fastjson
步骤:
1.引入jar包
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
2.配置消息转换器
<mvc:annotation-driven conversion-service="conversionService">
<!--配置消息转换器-->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
13.文件的上传单个与多个以及文件下载
1.单个文件上传
1.1 简介
SpringMVC对文件上传提供了支持,基于commons-fileupload
1.2 用法
步骤:
1.添加jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
2.编写上传页面
注意:因为是上传文件,所以需要使用enctype属性指定上传类型
<form action="${pageContext.request.contextPath}/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="multipartFile"/><br>
<input type="submit" value="上传"/>
</form>
3.配置文件解析器
注意:因为文件使用的是二进制格式,所以需要配置文件解析器
<!--配置文件解析器 id名称必须为multipartResolver-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
4.创建Controller
注意:因为上传的文件数据是从请求参数中来,所以需要添加@RequestParam
注解
@Controller
@RequestMapping("/file")
public class FileController {
@RequestMapping("/upload")
public String upload(@RequestParam CommonsMultipartFile multipartFile) throws IOException {
System.out.println(multipartFile);
System.out.println("文件名:"+multipartFile.getOriginalFilename());
System.out.println("表单名称:"+multipartFile.getName());
//指定上传的位置
String path = "D:/";
//获取上传的文件的文件名
String filename = multipartFile.getOriginalFilename();
//上传
multipartFile.transferTo(new File(path,filename));
return "success";
}
}
2.多个文件上传
步骤:
1.编写上传页面
<form action="${pageContext.request.contextPath}/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="multipartFiles"/><br>
<input type="file" name="multipartFiles"/><br>
<input type="file" name="multipartFiles"/><br>
<input type="submit" value="上传"/>
</form>
2.编写Controller
@Controller
@RequestMapping("/file")
public class FileController {
@RequestMapping("/upload")
public String upload(@RequestParam CommonsMultipartFile[] multipartFiles, HttpSession session) throws IOException {
//指定上传的位置
String path = "D:/";
for (CommonsMultipartFile img : multipartFiles) {
//获取上传的文件的文件名
String filename = img.getOriginalFilename();
//上传
img.transferTo(new File(path,filename));
}
return "success";
}
}
3.文件下载
步骤:
1.编写下载页面
<a href="${pageContext.request.contextPath}/file/download">点击下载</a>
2.创建Controller
@RequestMapping("/download")
public ResponseEntity<byte[]> download() throws IOException {
//指定下载文件
File file = new File("D:/美女.png");
//通过输入流将文件传入
FileInputStream is = new FileInputStream(file);
//创建字节数组,并将数组大小设置为预估的文件字节数
byte[] bytes = new byte[is.available()];
//将输入流中的字符存储到缓存数组中
is.read(bytes);
//获取下载显示的文件名,并解决中文乱码
String name = file.getName();
String downloadFileName = new String(name.getBytes("UTF-8"), "ISO-8859-1");
//设置Http响应头信息,并且通知浏览器以附件形式进行下载
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("Content-Disposition","attachment;filename="+downloadFileName);
//设置Http响应状态信息 OK代表正常
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, httpHeaders, status);
return responseEntity;
}
网友评论