springmvc第二天
学习目标
- 掌握图片上传(重点)
- 了解SpringMVC的统一异常处理
- 掌握SpringMVC拦截器(重点)
- 将面面项目改成ssm架构(重点)
第一章 - SpringMVC 实现文件上传
知识点-文件上传介绍
1.目标
- 掌握文件上传的要求
2.路径
- 文件上传概述
- 文件上传要求
- 常见的文件上传jar包和框架
3.讲解
3.1文件上传概述以及使用场景
就是把客户端(浏览器)的文件保存一份到服务器 说白了就是文件的拷贝
常见的使用场景:上传头像、上传各种照片、上传word、Excel等等文件
3.2文件上传要求
3.2.1 浏览器端要求(通用浏览器的要求)
- 表单提交方式 post
- 提供文件上传框(组件) input type=“file”
- 表单的entype属性必须为
multipart/form-data
(没有这个属性值的话, 文件的内容是提交不过去的)
3.2.2 服务器端要求
-
获取客户端上传的文件
- 准备一个目录存储客户端上传的文件
- 将客户端上传的文件写入到准备好的目录中
注意:
- 若表单使用了 multipart/form-data ,使用原生request.getParameter()去获取参数的时候都为null
我们做文件上传一般会借助第三方组件(jar, 框架 SpringMVC)实现文件上传.
3.3常见的文件上传jar包和框架
serlvet3.0(原生的文件上传的API)
commons-fileupload : apache出品的一款专门处理文件上传的工具包 (我们肯定不会直接使用)
struts2(底层封装了:commons-fileupload)
SpringMVC(底层封装了:commons-fileupload)
4.小结
案例-springmvc 传统方式文件上传
1.需求
- 使用springmvc 完成传统方式文件上传
2.步骤
- 把commons-fileupload坐标导入进来
- 在控制器的方法的形参里面定义和文件相关的变量 MultipartFile
- 把文件存到服务器
- 配置文件解析器
3.实现
- 创建Maven工程,添加依赖
<dependencies>
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</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>
- 创建前端页面
<h1>一,springmvc传统方式文件上传</h1>
<form action="springmvc/fileUpload02" method="post" enctype="multipart/form-data">
图片: <input type="file" name="upload"/><br/>
图片描述:<input type="text" name="pdesc"/>
<input type="submit" value="上传"/>
</form>
- 控制器
package com.itheima.controller;
import com.itheima.utils.UploadUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
/**
* 包名:com.itheima.controller
* @author Leevi
* 日期2020-08-15 08:46
* 1. 获取客户端传入的文件描述信息
* 2. 获取客户端上传的文件,存放到file文件夹中
* 2.1 获取客户端上传的文件 MultipartFile upload
* 2.2 创建一个file文件夹
* 2.3 使用输出流将客户端上传的文件,输出到file文件夹中
*/
@RestController
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload")
public String upload(String pdesc, MultipartFile upload, HttpServletRequest request){
System.out.println("文件描述是:" + pdesc);
//1. 获取存放文件的目录路径
String realPath = request.getSession().getServletContext().getRealPath("file/"+ UploadUtils.getDir());
File file = new File(realPath);
//判断file对应的文件夹是否真实存在于硬盘中
if (!file.exists()) {
//不存在,则将其在硬盘中创建出来
file.mkdirs();
}
//2. 将客户端上传的文件,写入到file文件夹中
//2.1 获取客户端上传的那个文件的文件名
String filename = upload.getOriginalFilename();
//将文件名,进行重命名,重命名成唯一的文件名--->UUID
String uuidName = UploadUtils.getUUIDName(filename);
try {
//2.2 将客户端上传的文件写入到文件夹中
upload.transferTo(new File(file,uuidName));
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
-
在springmvc.xml配置文件解析器
注意:文件上传的解析器id 是固定的,不能起别的名称,否则无法实现请求参数的绑定。(不光是文件,其他字段也将无法绑定)
<!--配置文件上传解析器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为 5MB -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
4.小结
案例-springmvc 跨服务器方式的文件上传(了解)
1.需求
- 了解使用springmvc 跨服务器方式的文件上传
2.分析
2.1分服务器的目的
在实际开发中,我们会有很多处理不同功能的服务器(注意:此处说的不是服务器集群)。 例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
缓存和消息服务器:负责处理高并发访问的缓存和消息
文件服务器:负责存储用户上传文件的服务器。
分服务器处理的目的是让服务器各司其职,从而提高我们项目的运行效率。
2.2跨服务器方式的文件上传图解
- 准备两个服务器(默认情况下,tomcat是不允许其他服务器往它里面写入数据的), 修改tomcat的的conf目录下的web.xml, 添加readonly参数为false
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JXAQlK5x-1631055241664)(img/tu_4.png)]
3.实现
- 添jersey依赖 (跨服务器上传图片的代码)
<dependencies>
<!--引入文件上传的依赖-->
<!--文件上传组件的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--springmvc的依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.2.RELEASE</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>
<!--跨服务器上传的文件的依赖-->
<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>
</dependencies>
- 前端页面
<h1>二,springmvc 跨服务器方式的文件上传</h1>
<form action="springmvc/fileUpload03" method="post" enctype="multipart/form-data">
图片: <input type="file" name="upload"/><br/>
图片描述:<input type="text" name="pdesc"/>
<input type="submit" value="上传"/>
</form>
- 控制器
package com.itheima.controller;
import com.itheima.utils.UploadUtils;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* 包名:com.itheima.controller
*
* @author Leevi
* 日期2020-08-15 09:53
*/
@RestController
@RequestMapping("/file")
public class FileController {
@PostMapping("/upload")
public String upload(String pdesc, MultipartFile upload){
System.out.println("pdesc="+pdesc);
//1. 获得文件名
String filename = upload.getOriginalFilename();
//2. 获得随机文件名
String uuidName = UploadUtils.getUUIDName(filename);
//3. 使用跨服务器文件上传的方式,将客户端上传的文件写入到文件服务器中
Client client = Client.create();
//连接文件服务器
WebResource resource = client.resource("http://localhost:8833/file/"+uuidName);
//通过resource将客户端上传的文件写入到文件服务器
try {
resource.put(upload.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
return "success";
}
}
4.小结
第二章-SpringMVC 中的异常处理(了解)
知识点-SpringMVC 中的异常处理
1.目标
- 掌握SpringMVC的统一异常处理
2.分析
系统中异常包括两类:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。
系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:
springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。
3.代码实现
3.1自定义异常处理器
package com.itheima.handler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 包名:com.itheima.handler
* @author Leevi
* 日期2020-08-15 10:30
* 1. 自定义一个异常处理器类,实现HandlerExceptionResolver接口
* 2. 重写resolveException方法,对异常进行统一处理
* 3. 在springmvc的配置文件中,配置异常处理器
*/
public class GlobalExceptionHandler implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg",ex.getMessage());
//打印异常信息
ex.printStackTrace();
modelAndView.setViewName("error");
return modelAndView;
}
}
3.2配置异常处理器
- 在springmvc.xml配置
<!--配置异常处理器-->
<bean id="sysExceptionResolver" class="com.itheima.handler.GlobalExceptionHandler"></bean>
4.小结
第三章-SpringMVC 中的拦截器(掌握)
知识点-SpringMVC入门
1.目标
- 掌握SpringMVC基本使用
2.路径
- 拦截器概述
- 自定义拦截器入门
3.讲解
3.1.拦截器概述
Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器(自己编写的Controller)进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。说到这里,可能大家脑海中有了一个疑问,这不是我们之前学的过滤器吗?是的它和过滤器是有几分相似,但
是也有区别,接下来我们就来说说他们的区别:
类别 | 使用范围 | 拦截范围 |
---|---|---|
拦截器 | SpringMVC项目 | 只会拦截访问的控制器方法的请求 |
过滤器 | 任何web项目 | 任何资源(servlet,控制器,jsp,html等) |
我们要想自定义拦截器, 要求必须实现: HandlerInterceptor 接口。
3.2.自定义拦截器入门
- 编写一个普通类实现 HandlerInterceptor 接口
package com.itheima.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 包名:com.itheima.interceptor
*
* @author Leevi
* 日期2020-08-15 10:57
* 1. 自定义一个拦截器实现HandlerInterceptor接口
* 2. 重写它的方法
* preHandle:在执行处理器方法之前执行
* postHandle:执行处理器方法之后执行
* afterCompletion:这次请求完成之后执行
* 3. 在springmvc的配置文件中,配置拦截器
*/
public class PermissionInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("进行权限校验....");
//返回true表示放行,返回false表示拦截
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("权限校验的posthandle方法执行了...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("权限校验的afterCompletion方法执行了...");
}
}
- 在springmvc.xml配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--排除某些请求-->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<bean id="interceptor2" class="com.itheima.interceptor.CheckNameInterceptor"> </bean>
</mvc:interceptor>
</mvc:interceptors>
4.小结
知识点-自定义拦截器进阶
1.目标
- 掌握自定义拦截器的高级使用
2.路径
- 拦截器的放行
- 拦截后跳转
- 拦截器的路径
- 拦截器的其它方法
- 多个拦截器执行顺序
3.讲解
3.1拦截器的放行
3.2拦截后跳转
拦截器的处理结果,莫过于两种:
放行: 如果后面还有拦截器就执行下一个拦截器,如果后面没有了拦截器,就执行Controller方法
拦截: 但是注意,拦截后也需要返回到一个具体的结果(页面,Controller)。
- 在preHandle方法返回false,通过request进行转发,或者通过response对象进行重定向,输出
package com.itheima.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 包名:com.itheima.interceptor
* @author Leevi
* 日期2020-08-15 11:12
*/
public class CheckNameInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("校验用户名...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("校验用户名的postHandler方法...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("校验用户名的afterCompletion方法...");
}
}
3.3 拦截器的路径
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--
拦截访问所有controller的请求
-->
<mvc:mapping path="/**"/>
<!--排除某些请求-->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<bean id="interceptor2" class="com.itheima.interceptor.CheckNameInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!--
拦截所有满足"/hello/say*"的请求
-->
<mvc:mapping path="/hello/say*"/>
<bean id="intercepter01" class="com.itheima.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
3.4拦截器的其它方法
- afterCompletion 在目标方法完成视图层渲染后执行。
- postHandle 在目标方法执行完毕获得了返回值后执行。
- preHandle 被拦截的目标方法执行之前执行。
package com.itheima.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 包名:com.itheima.interceptor
*
* @author Leevi
* 日期2020-08-15 11:12
*/
public class CheckNameInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("校验用户名...");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("校验用户名的postHandler方法...");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("校验用户名的afterCompletion方法...");
}
}
3.5 多个拦截器执行顺序
回想多个过滤器的执行顺序:
-
如果采用配置文件方式配置过滤器,那么就按照过滤器的配置先后顺序执行
2. 如果采用注解方式配置过滤器,那么就按照类名的排序执行
我们可以配置多个拦截器, 所以就存在一个优先级问题了.多个拦截器的优先级是按照配置的顺序决定的。
- 配置顺序
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<!--排除某些请求-->
<mvc:exclude-mapping path="/hello/sayHaha.do"/>
<bean id="interceptor2" class="com.itheima.interceptor.CheckNameInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!--用于指定拦截路径-->
<mvc:mapping path="/hello/say*"/>
<bean id="intercepter01" class="com.itheima.interceptor.PermissionInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
4.小结
第四章-将面面项目改成SSM
第一步-引入依赖
- spring相关依赖
- spring-webmvc
- spring-jdbc
- aop依赖
- mybatis整合spring的依赖
- log相关依赖
- jackson相关的依赖
- druid连接池依赖
- 文件上传的依赖
- 并且去掉heimaMvc的依赖
<properties>
<spring.version>5.0.2.RELEASE</spring.version>
<!--日志打印框架-->
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- log end -->
<!--
关键: mybatis整合spring的依赖
-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!--druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.5</version>
</dependency>
<!--SpringAOP相关的坐标-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
第二步-删除mybatis的核心配置文件
第三步-编写spring整合mybatis的配置文件
- 整合mybatis
- 配置事务管理者
- 加载事务注解驱动
第三步-编写spring的主配置文件
- 包扫描
- 加载mvc注解驱动
- 导入application-mybatis.xml
第四步-修改web.xml配置
- 将heimaMVC中的DispatcherServlet的配置改成SpringMVC中的DispatcherServlet的配置
- 将解决乱码的过滤器的配置改成SpringMVC中的解决乱码的过滤器配置
- 删除项目中自己定义的解决乱码的过滤器
第五步-修改各个controller的代码
- 将原本heimaMvc的Controller注解改成springMvc中的RestController注解
- 使用Autowired注解注入Service对象
- 在各个Controller类上添加RequestMapping注解
- 将Controller类的各个方法上的RequestMapping注解改成SpringMVC中的RequestMapping注解,并且修改路径
- 将各个方法的获取请求参数的方式改成SpringMVC中的获取请求参数
- 将各个方法的响应数据给客户端的方式改成SpringMVC的响应数据方式
第六步-修改各个Service的代码
- 将所有的Service的实现类改名成"XXXImpl"
- 给各个实现类添加接口,然后Controller中一定要以接口类型接收Service的对象
- 各个Service的实现类商添加Service注解进行IOC
- 使用Autowired注解注入Dao对象
- 将方法中所有涉及到SqlSession的代码全部删掉,直接就能使用Dao对象
- 要进行事务控制的类或者方法上添加Transactional注解
第七步-修改文件上传的代码
- 将原来的获取上传文件的代码改成SpringMVC的文件上传代码
- 在创建spring文件上传的配置文件,配置文件解析器