SpringMVC的组件
一、前端控制器
DispatcherServlet:前端控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
<!-- 前端控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始化参数,用于读取 SpringMVC 的配置文件 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<!-- 配置 servlet 的对象的创建时间点:加载时创建DispatcherServlet。
取值只能是非 0 正整数,表示启动顺序 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
二、处理器映射器
HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
三、处理器
Handler:处理器
它就是我们开发中要编写的具体业务控制器。由 DispatcherServlet 把用户请求转发到 Handler。由 Handler 对具体的用户请求进行处理。
HandlAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
四、视图解析器
View Resolver:视图解析器
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
<!-- 视图解析器对象 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
五、 <mvc:annotation-driven> 开启对注解的支持
在 SpringMVC 的各个组件中,处理器映射器、处理器适配器、视图解析器称为 SpringMVC 的三大组件。
在 SpringMVC.xml 配 置 文 件 中 使 用 <mvc:annotation-driven>替代RequestMappingHandlerMapping处理器和RequestMappingHandlerAdapter适配器的配置。
六、自定义类型转换器
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcase.utils.StringToDateConverter"/>
</set>
</property>
</bean>
七、解决中文乱码
<!-- 配置解决中文乱码的过滤器 -->
<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>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
SpringMVC的入门案例
一、SpringMVC的入门程序
1. 创建WEB工程,引入依赖的jar包
<properties>
<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>
2. 配置核心的控制器(配置DispatcherServlet)
在web.xml配置文件中核心控制器DispatcherServlet
<!-- 前端控制器 -->
<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对象被创建 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
3. 编写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.itcase"/>
<!-- 视图解析器对象 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 配置自定义类型转换器 -->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="cn.itcase.utils.StringToDateConverter"/>
</set>
</property>
</bean>
<!-- 开启SpringMVC框架注解的支持 -->
<mvc:annotation-driven conversion-service="conversionService"/>
</beans>
4. 编写index.jsp和HelloController控制器类
5. 在WEB-INF目录下创建pages文件夹,编写success.jsp的成功页面
二、 入门案例的执行过程分析
入门案例的执行流程
1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以服务器启动会创建DispatcherServlet对象, 就会加载springmvc.xml配置文件
2. 开启了注解扫描,那么HelloController对象就会被创建
3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解 找到执行的具体方法
4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件
5. Tomcat服务器渲染页面,做出响应
三、 RequestMapping 注解
用于建立请求 URL 和处理请求方法之间的对应关系。
出现位置:
- 类上:请求 URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。写的话需要以/开头。它出现的目的是为了使我们的 URL 可以按照模块化管理:
例如:账户模块:有很多增删改方法 /account/add /account/update /account/delete
- 方法上:请求 URL 的第二级访问目录。
属性:
- path 指定请求路径的url
- value value属性和path属性是一样的
- mthod 指定该方法的请求方式
- params 指定限制请求参数的条件
- headers 发送的请求中必须包含的请求头
常用的注解
一、 RequestParam注解
1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
2. 属性:
value:请求参数中的名称
required:请求参数中是否必须提供此参数,默认值是true,必须提供
二、RequestBody注解
1. 作用:把请求中的指定名称的参数传递给控制器中的形参赋值
2. 属性:
value:请求参数中的名称
required:请求参数中是否必须提供此参数,默认值是true,必须提供
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println("执行了...");
System.out.println(body);
return "success";
}
<form action="anno/testRequestBody" method="post">
用户姓名:<input type="text" name="username"/><br/>
用户年龄:<input type="text" name="age"/><br/>
<input type="submit" name="提交"/>
</form>
三、RequestHeader注解
1. 作用:获取指定请求头的值
2. 属性:value:请求头的名称
@RequestMapping(value = "/testRequestHeader")
public String testRequestHeader(@RequestHeader(value="Accept") String header){
System.out.println("执行了...");
System.out.println(header);
return "success";
}
四、CookieValue注解
1. 作用:用于获取指定cookie的名称的值
2. 属性:value:cookie的名称
@RequestMapping(value = "/testCookieValue")
public String testCookieValue(@CookieValue(value="JSESSIONID") String cookieValue){
System.out.println("执行了...");
System.out.println(cookieValue);
return "success";
}
五、 ModelAttribute注解
1. 作用:
出现在方法上:表示当前方法会在控制器方法执行前线执行。
出现在参数上:获取指定的数据给参数赋值。
2. 应用场景:当提交表单数据不是完整的实体数据时,保证没有提交的字段使用数据库原来的数据。
六、SessionAttributes注解
1. 作用:用于多次执行控制器方法间的参数共享
2. 属性:value:指定存入属性的名称
@RequestMapping(value = "/testSessionAttributes")
public String testSessionAttributes(Model model){
System.out.println("testSessionAttributes执行了...");
//底层会存储到request域对象中
model.addAttribute("msg","张三");
return "success";
}
/**
* 得到session域中的值
* @return
*/
@RequestMapping(value = "/getSessionAttributes")
public String getSessionAttributes(ModelMap modelMap){
String msg = (String) modelMap.get("msg");
System.out.println(msg);
return "success";
}
响应数据和结果视图
一、返回值分类
1. 返回字符串
Controller方法返回字符串可以指定逻辑视图的名称,根据视图解析器为物理视图的地址。
/**
* 返回值类型为字符串
* @param model
* @return
*/
@RequestMapping("/testString")
public String testString(Model model){
System.out.println("testString方法执行了");
//模拟从数据库中查询User对象
User user = new User();
user.setUsername("美美");
user.setPassword("123");
user.setAge(30);
//model对象
model.addAttribute("user",user);
return "success";
}
2. 返回值是void
如果控制器的方法返回值编写成void,执行程序报404的异常,默认查找JSP页面没有找到。
默认会跳转到@RequestMapping(value="/initUpdate") initUpdate的页面。
可以使用请求转发或者重定向跳转到指定的页面
**
* 返回值类型为void
* 请求转发一次转发,不用编写项目名称
* 重定向两次请求,写项目名
*/
@RequestMapping("/testVoid")
public void testVoid(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("testVoid方法执行了");
//编写请求转发的程序
// request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
//重定向
// response.sendRedirect(request.getContextPath()+"/index.jsp");
//解决中文乱码
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//直接进行响应
response.getWriter().write("你好");
return;
}
3. 返回值是ModelAndView对象
ModelAndView对象是Spring提供的一个对象,可以用来调整具体的JSP视图
@RequestMapping("/testModelAndView")
public ModelAndView testModelAndView(){
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
System.out.println("testModelAndView方法执行了");
//模拟从数据库中查询User对象
User user = new User();
user.setUsername("科比");
user.setPassword("2020");
user.setAge(39);
//把user对象存储到mv对象中,也会把user对象存入到request对象
mv.addObject("user",user);
//跳转到哪个页面
mv.setViewName("success");
return mv;
}
4. SpringMVC框架提供的转发和重定
/**
* 使用关键字的方式进行转发或者重定向
* @return
*/
@RequestMapping("/testForwardOrRedirect")
public String testForwardOrRedirect(){
System.out.println("testForwardOrRedirect方法执行了");
//请求的转发
//return "forward:/WEB-INF/pages/success.jsp";
//重定向
return "redirect:/index.jsp";
}
二、 ResponseBody响应json数据
1. DispatcherServlet会拦截到所有的资源,导致一个问题就是静态资源(img、css、js)也会被拦截到,从而不能被使用。需要配
置静态资源不进行拦截,在springmvc.xml配置文件添加如下配置
mvc:resources标签配置不过滤
location元素表示webapp目录下的包下的所有文件
mapping元素表示以/static开头的所有请求路径,如/static/a 或者/static/a/b
<!-- 告诉前端控制器,哪些静态资源不拦截 -->
<mvc:resources location="/css/" mapping="/css/**"/>
<mvc:resources location="/images/" mapping="/images/**"/>
<mvc:resources location="/js/" mapping="/js/**"/>
2. 使用@RequestBody注解把json字符串和JavaBean对象的转换
/**
* 模拟异步请求响应
* @return
*/
@RequestMapping("/testAjax")
public @ResponseBody User testAjax(@RequestBody User user){
System.out.println("testAjax方法执行了");
//客户端发送ajax的请求,传的是json字符串,后端把json字符串封装到user对象中
System.out.println(user);
//做响应,模拟查询数据库
user.setUsername("haha");
user.setAge(40);
//做响应
return user;
}
<script src="js/jquery.min.js"></script>
<script>
// 页面加载,绑定单击事件
$(function(){
$("#btn").click(function(){
// alert("hello btn");
// 发送ajax请求
$.ajax({
// 编写json格式,设置属性和值
url:"user/testAjax",
contentType:"application/json;charset=UTF-8",
data:'{"username":"hehe","password":"123","age":30}',
dataType:"json",
type:"post",
success:function(data){
// data服务器端响应的json的数据,进行解析
alert(data);
alert(data.username);
alert(data.password);
alert(data.age);
}
});
});
});
SpringMVC实现文件上传
一、 web阶段文件上传
1. 导入文件上传的jar包
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
2. 编写文件上传的jsp页面
<h3>传统文件上传</h3>
<form action="user/fileupload1" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
<input type="submit" value="上传"/>
</form>
3. 编写文件上传的Controller控制器
/**
* 传统的文件上传
* @return
*/
@RequestMapping("/fileupload1")
public String fileupload1(HttpServletRequest request) throws Exception {
System.out.println("文件上传....");
//使用fileupload组件完成文件上传
//上传的位置,getSession().getServletContext()得到最大域对象
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断路径是否存在
File file = new File(path);
if(!file.exists()){
//创建改文件夹
file.mkdirs();
}
//解析request对象,获取上传文件项
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//解析request
List<FileItem> items = upload.parseRequest(request);
//遍历文件项
for (FileItem item : items) {
//进行判断,当前item对象是否是上传文件项
if(item.isFormField()){
//说明普通表单项
}else{
//说明上传文件项
//获取上传文件的名称
String filename = item.getName();
//把文件的名称设置唯一值 uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
//完成文件上传
item.write(new File(path,filename));
//删除临时文件
item.delete();
}
}
System.out.println(path);
return "success";
}
二、SpringMVC传统方式文件上传
SpringMVC框架提供了MultipartFile对象,该对象表示上传的文件,要求变量名称必须和表单file标签的 name属性名称相同。
1. 编写文件上传的jsp页面
name的upload,与方法变量名称upload保持一致
<h3>SpringMVC文件上传</h3>
<form action="user/fileupload2" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
<input type="submit" value="上传"/>
</form>
2. 编写文件上传的Controller控制器
/**
* springmvc文件上传
* @return
*/
@RequestMapping("/fileupload2")
public String fileupload2(HttpServletRequest request, MultipartFile upload) throws IOException {
System.out.println("Springmvc文件上传....");
//使用fileupload组件完成文件上传
//上传的位置,getSession().getServletContext()得到最大域对象
String path = request.getSession().getServletContext().getRealPath("/uploads/");
//判断路径是否存在
File file = new File(path);
if(!file.exists()){
//创建该文件夹
file.mkdirs();
}
//获取上传文件的名称
String filename = upload.getOriginalFilename();
//把文件的名称设置唯一值 uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
//完成文件上传
upload.transferTo(new File(path,filename));
return "success";
}
3. 配置文件解析器对象
<!-- 配置文件解析器对象 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="1048576"/>
</bean>
三、SpringMVC跨服务器方式文件上传
1. 搭建图片服务器,更改端口号,在webapp目录下创建uploads文件夹,用于保存上传图片
2. 实现SpringMVC跨服务器方式文件上传
1)导入开发需要的jar包
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-core</artifactId>
<version>1.18.1</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.18.1</version>
</dependency>
2)编写文件上传的JSP页面
<h3>跨服务器方式文件上传</h3>
<form action="user/fileupload3" method="post" enctype="multipart/form-data">
选择文件:<input type="file" name="upload"/><br>
<input type="submit" value="上传"/>
</form>
3)编写控制器
/**
* 跨服务器文件上传
* @return
*/
@RequestMapping("/fileupload3")
public String fileuoload3(MultipartFile upload) throws Exception {
System.out.println("跨服务器文件上传...");
// 定义上传文件服务器路径
String path = "http://localhost:9090/uploads/";
// 获取上传文件的名称
String filename = upload.getOriginalFilename();
// 把文件的名称设置唯一值,uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
filename = uuid+"_"+filename;
// 创建客户端的对象
Client client = Client.create();
// 和图片服务器进行连接
WebResource webResource = client.resource(path + filename);
// 上传文件
webResource.put(upload.getBytes());
return "success";
}
tomcat服务器不支持put和delete请求,需要在web.xml中进行配置
<init-param>
<param-name>readonly</param-name>
<param-value>false</param-value>
</init-param>
SpringMVC的异常处理和拦截器
一、异常处理
1. 异常处理逻辑
Controller调用service,service调用dao,异常都是向上抛出的,最终D由ispatcherServlet找异常处理器进行异常的处理。
2. SpringMVC的异常处理
2.1 自定义异常类
public class SysException extends Exception{
//异常提示信息
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public SysException(String message) {
this.message = message;
}
}
2.2 自定义异常处理器
在springmvc中配置异常处理器
<!-- 配置异常处理器 -->
<bean id="sysExceptionResolver" class="cn.itcast.exception.SysExceptionResolver"/>
自定义异常处理器实现 HandlerExceptionResolver接口
public class SysExceptionResolver implements HandlerExceptionResolver {
/**
* 处理异常业务逻辑
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//获取异常对象
SysException e = null;
if(ex instanceof SysException){
e = (SysException) ex;
}else{
e = new SysException("系统正在维护...");
}
//创建ModelAndView对象
ModelAndView mv = new ModelAndView();
mv.addObject("errorMsg",e.getMessage());
//跳转到error页面
mv.setViewName("error");
return mv;
}
}
二、SpringMVC框架中的拦截器
1. 拦截器概述
- SpringMVC框架中的拦截器用于对处理器进行预处理和后处理的技术。
- 可以定义拦截器链,连接器链就是将拦截器按着一定的顺序结成一条链,在访问被拦截的方法时,拦截器链中的拦截器会按着定义的顺序执行。
- 拦截器和过滤器的功能比较类似,有区别 :
- 过滤器是Servlet规范的一部分,任何框架都可以使用过滤器技术。
- 拦截器是SpringMVC框架独有的。
- 过滤器配置了/*,可以拦截任何资源。
- 拦截器只会对控制器中的方法进行拦截。
拦截器也是AOP思想的一种实现方式,想要自定义拦截器,需要实现HandlerInterceptor接口。
2. 自定义拦截器
2.1 创建类,实现HandlerInterceptor接口,重写需要的方法
public class MyInterceptor1 implements HandlerInterceptor {
/**
* 预处理,controller方法执行前
* return true 放行,执行下一个拦截器,如果没有,执行controller中的方法
* 可以做一些逻辑的判断,例如没有登录转去登陆页面
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("MyInterceptor1执行了...前");
//出问题跳转页面
//request.getRequestDispatcher("/WEB-INF/pages/error.jsp").forward(request,response);
return true;
}
/**
* 后处理方法,controller方法执行后,success.jsp执行之前
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor1执行了...后");
}
/**
* success.jsp页面执行后,该方法会执行
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("MyInterceptor1执行...最后");
}
}
2. 在springmvc.xml中配置拦截器类
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 要拦截的具体方法 -->
<mvc:mapping path="/user/*"/>
<!-- 配置拦截器对象 -->
<bean class="cn.itcast.interceptor.MyInterceptor1"/>
</mvc:interceptor>
<!-- 配置第二个拦截器 -->
<mvc:interceptor>
<!-- 要拦截的具体方法 -->
<mvc:mapping path="/**"/>
<!-- 配置拦截器对象 -->
<bean class="cn.itcast.interceptor.MyInterceptor2"/>
</mvc:interceptor>
3. HandlerInterceptor接口中的方法