一、上传文件
⊙客户端
1-客户端表单3要素
2、文件上传原理
⊙服务器端
1、单文件上传步骤
①pom.xml导包
导入fileupload和io坐标
<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.3</version>
</dependency>
②springmvc.xml配置文件上传解析器
测试: ③controller编写代码
@RequestMapping("/quick16")
@ResponseBody
public void save16(String username, MultipartFile uploadFile) {//uploadFile要跟表单的name一致;MultipartFile是用来上传的文件的
System.out.println(username);
System.out.println(uploadFile);
}
输出:
lizhxi
org.springframework.web.multipart.commons.CommonsMultipartFile@49afbd7c
③保存文件:③controller编写代码
@RequestMapping("/quick16")
@ResponseBody
public void save16(String username, MultipartFile uploadFile) throws IOException {//uploadFile要跟表单的name一致;MultipartFile是用来上传的文件的
//获取上传文件名称
String originalFilename = uploadFile.getOriginalFilename();
//存储文件
uploadFile.transferTo(new File("C:\\aaa\\"+originalFilename));//transfer To:转移 到
}
2、多文件上传
①多参式
客户端:
<form action="${pageContext.request.contextPath}/user/quick16" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
文件1<input type="file" name="uploadFile"><br> <!--uploadFile-->
文件2<input type="file" name="uploadFile2"><br> <!--uploadFile2-->
<input type="submit" value="上传">
</form>
controller:
@RequestMapping("/quick16")
@ResponseBody //MultipartFile的引用变量一定要跟表单项一致,才能被注入
public void save16(String username, MultipartFile uploadFile, MultipartFile uploadFile2) throws IOException {//uploadFile要跟表单的name一致;MultipartFile是用来上传的文件的
//获取上传文件名称
String originalFilename = uploadFile.getOriginalFilename();
String originalFilename2 = uploadFile.getOriginalFilename();
//存储文件
uploadFile.transferTo(new File("C:\\aaa\\"+originalFilename));
uploadFile.transferTo(new File("C:\\aaa\\"+originalFilename2));
}
②数组式
客户端:
<form action="${pageContext.request.contextPath}/user/quick16" method="post" enctype="multipart/form-data">
名称<input type="text" name="username"><br>
文件1<input type="file" name="uploadFile"><br><!--uploadFile要一致-->
文件2<input type="file" name="uploadFile"><br>
文件2<input type="file" name="uploadFile"><br>
文件2<input type="file" name="uploadFile"><br>
文件2<input type="file" name="uploadFile"><br>
<input type="submit" value="上传">
</form>
controller:
@RequestMapping("/quick16")
@ResponseBody //MultipartFile的引用变量一定要跟表单项一致,才能被注入
public void save16(String username, MultipartFile[] uploadFile) throws IOException {//uploadFile要跟表单的name一致;MultipartFile是用来上传的文件的
//遍历数组
for (MultipartFile multipartFile : uploadFile) {
//获取上传文件名称
String originalFilename = multipartFile.getOriginalFilename();
//存储文件
multipartFile.transferTo(new File("C:\\aaa\\"+originalFilename));
}
}
二、SpringMVC拦截器
1、快速入门
①编写controller目标方法
@RequestMapping("/quick2")
public ModelAndView save2() {
System.out.println("我是目标方法。。");
//创建视图对象
ModelAndView modelAndView = new ModelAndView();
//存储数据到request
modelAndView.addObject("username", "LiZhiXi");
//绑定视图资源
modelAndView.setViewName("success"); //指定显示的页面(前后缀被配置了)
return modelAndView; //返回视图对象(转发页面)
}
②编写MyInterceptor1实现HandlerInterceptor接口
public class MyInterceptor1 implements HandlerInterceptor {
//执行:目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是preHandle。。。。");
return true;//false表示拦截访问资源
}
//执行:目标方法执行之后,视图对象返回之前
@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="/**"/>
<!--告诉spring我这个是拦截器-->
<bean class="com.itheima.controller.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
④index.jsp
<h2>Hello World!${name}</h2>
输出:
index.jsp
Hello World!LiZhiXi
控制台:
我是preHandle。。。。
我是目标方法。。
我是postHandle。。。。
我是afterCompletion。。。。
执行流程顺序:
2、拦截器方法演示
①preHandle
作用:【在执行目标方法之前执行】
一般是使用request获取参数来进行拦截操作
//执行:目标方法执行之前
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//拦截访问者获取param请求参数
String param = request.getParameter("param");
//判断请求参数是否存在or不一致
if ("yes".equals(param)){
//一致
return true; //放行访问
}else {
//没有or不一致,转发error页面
request.getRequestDispatcher("/jsp/error.jsp").forward(request,response);
return false;
}
}
②postHandle
特点:【目标方法返回视图对象之前(目标方法已经对视图对象进行了操作,只是还差返回这一步)】
一般用来操作视图对象
//执行:目标方法执行之后,视图对象返回之前
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//重新设置视图对象中的键值对
modelAndView.addObject("name","刘德华"); //将"lizhixi"改为“刘德华”
}
③拦截器链
使用多个拦截器,这里只使用2个来意思意思。
1、配置springmvc.xml
<!--配置拦截器1-->
<mvc:interceptors>
<mvc:interceptor>
<!--设置对哪些资源进行拦截操作:所有-->
<mvc:mapping path="/**"/>
<!--告诉spring我这个是拦截器-->
<bean class="com.itheima.controller.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
<!--配置拦截器2-->
<mvc:interceptors>
<mvc:interceptor>
<!--设置对哪些资源进行拦截操作:所有-->
<mvc:mapping path="/**"/>
<!--告诉spring我这个是拦截器-->
<bean class="com.itheima.controller.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
2、2个拦截器(省略)
这里要说的是,拦截器的优先执行顺序跟springmvc.xml配置的Bean的顺序有关。
- 如果是拦截器1Bean在前,拦截器2在后
- 如果是拦截器2Bean在前,拦截器1在后
发现,哪个最优先的拦截器先出发,回来的时候就迟。(filter一样)
三、拦截器案例:用户登录
1、分析
需求:用户必须登录才能访问资源
判断是否登录的依据:根据session是否有存储指定User对象来判断是否登录(服务器共享session对象域数据)
实现:自定义拦截器,并在preHandle进行判断。(有,放行;没有,跳转登录页面)
2、代码实现
1、springmvc.xml配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--设置对哪些资源进行拦截操作:所有-->
<mvc:mapping path="/**"/>
<!--告诉spring我这个是拦截器-->
<bean class="com.itheima.controller.PrivilegeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
2、自定义拦截器:
public class PrivilegeInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//判断用户是否登录,本质:判断session中是否存在user
User user = (User) request.getSession().getAttribute("user");
if (user==null){
//没有登录
response.sendRedirect(request.getContextPath()+"/login.jsp");
return false;
}
//放行,访问目标资源
return true;
}
}
3、客户端
表单提交的访问UserController中login方法。
<form action="${pageContext.request.contextPath}/user/login" method="post">
4、修改【springmvc.xml配置拦截器】
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--设置对哪些资源进行拦截操作:所有-->
<mvc:mapping path="/**"/>
<!--配置哪些资源被排除拦截-->
<mvc:exclude-mapping path="/user/login"/>
<!--告诉spring我这个是拦截器-->
<bean class="com.itheima.controller.PrivilegeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
5、UserController
@RequestMapping("/login")
public String login(String username, String password, HttpSession session) {//springMVC帮你注入Servlet原始API对象引用
//根据账户密码查询User
User user = userService.login(username, password);
//判断User是否存在
if (user != null) {
//User存在,登陆成功
//将User存储到session中,不然会被拦截器拦截
session.setAttribute("user",user);
// return "redirect:/index.jsp";
return "redirect:/index.jsp"; //使用转发更好:因为存储数据
}
//User不存在
return "redirect:/login.jsp"; //返回页面(View)
四、Spring异常处理机制
①异常处理思路
异常从Dao–>Service–>Controller,最后抛给前端控制器解决,因为前端控制器是最终调用者,而前端控制器去找SpringMVC内置的异常处理器。
②SpringMVC异常处理方式
1、简单异常处理器SimpleMappingExceptionResolver
解析:
“SimpleMappingExceptionResolver”接受到抛出的异常会先去
----------------------------------------↓下面这里寻找(自定义的异常响应)↓---------------------------------------------
<map> 异常类型 错误视图
<entry key="com.itheima.exception.MyException" value="error"/>
<entry key="java.lang.ClassCastException" value="error"/>
</map>
------------------------------------如果找不到,才去执行这里(默认异常响应)-------------------------------------
<property name=“defaultErrorView” value=“error”/> 默认错误视图
-----------------------------------下面是具体的介绍------------------------------
<property name=“defaultErrorView” value=“error”/>中name=“defaultErrorView”的defaultErrorView可能是简单异常处理器的属性吧,
“error”表示【视图(页面)】,即,当抛出了异常,而且是没有配置的异常,就去跳转到指定页面(index.jsp、login.jsp、、、)。
【问:为什么可以直接写页面的名称呢?】
答:原本不是的,只是我们在spring-mvc中配置了视图解析器,将网页的前缀后缀都配置了。
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
<map> 异常类型 错误视图
<entry key="com.itheima.exception.MyException" value="error"/>
<entry key="java.lang.ClassCastException" value="error"/>
</map>
key:表示异常的类的全限定名,当然这个“com.itheima.exception.MyException”是我自定义的异常(MyExpetion空的自定义类,继承了Exception)
value:同上
【问:跳转页面有什么用?】
当用户访问页面时出现异常,那么,如果在网页上直接报错显示500等等,用户体验不好。
我们可以使用遇到什么错,跳转什么页面的方式去“忽悠”用户。比如:访问人数较多,请稍后再来!~~
2、自定义异常处理
1、创建自定义异常处理器,实现HandlerExceptionResolver接口
instanceof :用来判断一个对象是否为一个类的实例
public class ExceptionDemo01 implements HandlerExceptionResolver {
/**
* 参数:Exception:将抛出的异常封装成异常对象
* 返回值:ModelAndView(视图):跳转到指定的错误页面
*/
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
//创建视图对象
ModelAndView modelAndView = new ModelAndView();
//判断异常类型
if (ex instanceof MyException){
//存储数据
modelAndView.addObject("error","自定义异常");
modelAndView.setViewName("error1");//跳转视图
}else if (ex instanceof ClassCastException){
modelAndView.addObject("error","格式转换异常");
modelAndView.setViewName("error2");//跳转视图
}
return modelAndView;
}
}
2、springmvc.xml配置异常处理器
<!--配置自定义异常处理器-->
<bean class="com.itheima.myException.ExceptionDemo01"/>
3、测试异常(省略)
如果出错的异常类型匹配就跳转相应的页面。
总结
spring-mvc.xml总配置
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--Controller组件扫描:让Spring去指定类扫描注解-->
<context:component-scan base-package="com.itheima.controller"/>
<!--配置内部资源视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前后缀-->
<property name="prefix" value="/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--配置处理映射器器
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"></bean>
</list>
</property>
</bean>-->
<!--放行访问web应用资源限制-->
<!--①-->
<!-- <mvc:resources mapping="/js/**" location="/js/"/><!–mapping:表示浏览器访问的映射地址;location:表示映射资源的实际地址–>-->
<!-- <mvc:resources mapping="/img/**" location="/img/"/>-->
<!--②-->
<mvc:default-servlet-handler/>
<!-- 表示SpringMVC帮你找资源,找不到就交给Tomcat服务器(Tomcat容器内找)-->
<!--mvc的注解驱动-->
<mvc:annotation-driven conversion-service="conversionService"/>
<!--声明类型转换器-->
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters"><!--设置属性-->
<list>
<bean class="com.itheima.converter.DateConverter"/> <!--叫工厂Bean帮我造个自定义转换器-->
</list>
</property>
</bean>
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--上传文件的总大小-->
<property name="maxInMemorySize" value="1024000"/>
<!--单个文件上传的大小-->
<property name="maxUploadSizePerFile" value="102400"/>
<!--上传文件的编码类型-->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
<!-- <!–配置拦截器1–>
<mvc:interceptors>
<mvc:interceptor>
<!–设置对哪些资源进行拦截操作:所有–>
<mvc:mapping path="/**"/>
<!–告诉spring我这个是拦截器–>
<bean class="com.itheima.controller.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
<!–配置拦截器2–>
<mvc:interceptors>
<mvc:interceptor>
<!–设置对哪些资源进行拦截操作:所有–>
<mvc:mapping path="/**"/>
<!–告诉spring我这个是拦截器–>
<bean class="com.itheima.controller.MyInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>-->
<!-- <!–配置拦截器–>
<mvc:interceptors>
<mvc:interceptor>
<!–设置对哪些资源进行拦截操作:所有–>
<mvc:mapping path="/**"/>
<!–配置哪些资源被排除拦截–>
<mvc:exclude-mapping path="/user/login"/>
<mvc:exclude-mapping path="/user/quick"/>
<mvc:exclude-mapping path="/js/**"/>
<mvc:exclude-mapping path="/css/**"/>
<mvc:exclude-mapping path="/img/**"/>
<mvc:exclude-mapping path="/pages/**"/>
<mvc:exclude-mapping path="/plugins/**"/>
<!–告诉spring我这个是拦截器–>
<bean class="com.itheima.controller.PrivilegeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
-->
<!--配置自定义异常处理器-->
<bean class="com.itheima.myException.ExceptionDemo01"/>
</beans>
applicationComtext.xml总配置
<?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 http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 导入jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据库连接池对象-->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.url}"/>
<property name="jdbcUrl" value="${jdbc.driver}"/>
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置jdbc模板对象-->
<bean id="template" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="vo" class="com.itheima.domain.VO"/>
<!--配置userDao-->
<bean id="userDao" class="com.itheima.dao.Impl.UserDaoIpml">
</bean>
<!--配置UserService-->
<bean id="userService" class="com.itheima.service.Impl.UserServiceIpml">
<property name="dao" ref="userDao"/>
</bean>
<context:component-scan base-package="com.itheima"/>
</beans>