目录
1.SpringMVC实现文件上传
添加依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
页面
三要素:
- 必须以表单方式提交。
- 表单属性enctype必须为multipart/form-data
- 请求方式必须为post
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<form action="/user/fileUpload" method="post" enctype="multipart/form-data">
用户名:<input type="text" name="userName"><br/>
年龄:<input type="text" name="age"><br/>
生日:<input type="text" name="birthday"><br/>
性别:<input type="radio" name="gender" value="1">男
<input type="radio" name="gender" value="0">女<br/>
头像:<input type="file" name="photoFile"><br/>
<button type="submit">提交</button>
</form>
<br/>
</body>
</html>
spring-mvc.xml
配置多媒体解析器:CommonsMultipartResolver,其id必须是multipartResolver
<?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">
<context:component-scan base-package="com.study"/>
<!--对mvc组件进行增强-->
<!--<mvc:annotation-driven conversion-service="conversionServiceFactoryBean"/>-->
<mvc:annotation-driven/>
<!--配置自定义类型转换器-->
<!--<bean id="conversionServiceFactoryBean" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.study.converter.StringToDateConverter"/>
</set>
</property>
</bean>-->
<!--配置视图解析器-->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/><!--前缀-->
<property name="suffix" value=".jsp"/><!--后缀-->
</bean>
<!--配置多媒体解析器,id不可以随意填写-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5000000"/><!--设置文件最大字节-->
</bean>
</beans>
controller
形参接收必须为MultipartFile类型。
@Controller
@RequestMapping("/user")
public class UserController {
//形参接收类型必须为MultipartFile
@RequestMapping("/fileUpload")
public String fileUpload(User user, MultipartFile photoFile) throws IOException {
//获取文件原始名称
String originalFilename = photoFile.getOriginalFilename();
//文件保存路径
String filePath = "F://" + System.currentTimeMillis() + originalFilename;
//将文件存储到指定位置
photoFile.transferTo(new File(filePath));
user.setPhoto(filePath);
System.out.println(user);
return "success";//默认使用请求转发的方式跳转
}
}
2.请求转发
特点:
- 服务器内部转发。
- 浏览器地址栏不发生改变。
- 可以携带数据
2.1原生方式
使用HttpServletRequest、HttpServletResponse
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">原生方式请求转发</button>
</form>
<br/>
</body>
</html>
controller
@Controller
@RequestMapping("/user")
public class UserController {
//原生方式实现请求转发
@RequestMapping(value = "/login",name = "原生方式实现请求转发")
public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
User user = new User();
user.setUserName(userName);
user.setPassword(password);
request.setAttribute("user",user);
//原生方式不走前端控制器,所以要写全路径名。
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
}
//形参接收类型必须为MultipartFile
@RequestMapping("/fileUpload")
public String fileUpload(User user, MultipartFile photoFile) throws IOException {
//获取文件原始名称
String originalFilename = photoFile.getOriginalFilename();
//文件保存路径
String filePath = "F://" + System.currentTimeMillis() + originalFilename;
//将文件存储到指定位置
photoFile.transferTo(new File(filePath));
user.setPhoto(filePath);
System.out.println(user);
return "success";//默认使用请求转发的方式跳转
}
}
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
用户名:${user.userName}<br/>
姓名:${user.name}<br/>
密码:${user.password}<br/>
</body>
</html>
2.2forward关键字方式
使用Model模型存储数据。
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">原生方式请求转发</button>
</form>
<br/>
<form action="/user/login1" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">forward关键字请求转发</button>
</form>
<br/>
</body>
</html>
controller
@Controller
@RequestMapping("/user")
public class UserController {
//forward关键字实现请求转发,直接接收参数
@RequestMapping(value = "/login1",name = "原生方式实现请求转发")
public String login1(String userName, String password, Model model){
User user = new User();
user.setUserName(userName);
user.setPassword(password);
//将数据放到model模型中,其实就是放入了request域
model.addAttribute("user",user);
//不走前端控制器,所以要写全路径名。
return "forward:/WEB-INF/pages/success.jsp";
}
//原生方式实现请求转发
@RequestMapping(value = "/login",name = "原生方式实现请求转发")
public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
User user = new User();
user.setUserName(userName);
user.setPassword(password);
request.setAttribute("user",user);
//原生方式不走前端控制器,所以要写全路径名。
request.getRequestDispatcher("/WEB-INF/pages/success.jsp").forward(request,response);
}
//形参接收类型必须为MultipartFile
@RequestMapping("/fileUpload")
public String fileUpload(User user, MultipartFile photoFile) throws IOException {
//获取文件原始名称
String originalFilename = photoFile.getOriginalFilename();
//文件保存路径
String filePath = "F://" + System.currentTimeMillis() + originalFilename;
//将文件存储到指定位置
photoFile.transferTo(new File(filePath));
user.setPhoto(filePath);
System.out.println(user);
return "success";//默认使用请求转发的方式跳转
}
}
2.3简单方式
走视图解析器,有三种方式可以携带数据:
- 使用Model模型
//简单方式 @RequestMapping(value = "/login2",name = "简单方式实现请求转发") public String login2(String userName, String password, Model model){ User user = new User(); user.setUserName(userName); user.setPassword(password); //将数据放到model模型中,其实就是放入了request域 model.addAttribute("user",user); return "success"; }
- 使用HttpServletRequest
@RequestMapping(value = "/login2",name = "简单方式实现请求转发") public String login2(String userName, String password, HttpServletRequest request){ User user = new User(); user.setUserName(userName); user.setPassword(password); request.setAttribute("user",user); return "success"; }
- 使用ModelAndView
@RequestMapping(value = "/login2",name = "简单方式实现请求转发") public ModelAndView login2(String userName, String password, HttpServletRequest request){ ModelAndView modelAndView = new ModelAndView(); User user = new User(); user.setUserName(userName); user.setPassword(password); modelAndView.addObject("user",user);//存放数据 modelAndView.setViewName("success");//设置转发页面 return modelAndView; }
3.重定向
特点:
- 可以进行服务器外部转发.
- 浏览器地址栏发生改变.
- 无法携带数据
3.1原生方式
register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<from>
用户名:<input type="text" name="userName"/>
密码:<input type="password" name="password"/>
<button type="submit">注册</button>
</from>
</body>
</html>
login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/user/login" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">原生方式请求转发</button>
</form>
<br/>
<form action="/user/login1" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">forward关键字请求转发</button>
</form>
<br/>
<form action="/user/login2" method="post">
用户名:<input type="text" name="userName"><br/>
密码:<input type="password" name="password"><br/>
<button type="submit">简单方式请求转发</button>
</form>
<br/>
<a href="/user/toRegister">注册</a>
<br/>
</body>
</html>
controller
@RequestMapping(value = "/toRegister",name = "原生方式实现重定向")
public void toRegister(HttpServletResponse response) throws IOException {
response.sendRedirect("/register.jsp");//不走视图解析器
}
3.2Redirect关键字
controller
@RequestMapping(value = "/toRegister",name = "redirect关键字实现重定向")
public String toRegister(HttpServletResponse response) throws IOException {
return "redirect:/register.jsp";
}
4.@SessionAttributes
4.1向session中添加
在类上添加@SessionAttributes(values)注解,表示在这个类中,任何像request域中添加指定的value,就会向session中存一份。
属性也可以使用type,表示像request中添加指定类型的value,就会向session中存放。
4.2向session中清除
清除使用@SessionAttributes存入session的数据。
@RequestMapping("/cleanSession")
public String cleanSession(SessionStatus sessionStatus) throws Exception{
// 清除通过@SessionAttributes存储的数据
sessionStatus.setComplete();
return "success";
}
5.静态资源访问
问题:
我们将静态资源放在 webapp下的images下,在WEB-INF外的资源可以直接访问,但是直接访问这个静态资源时,404了。
这是因为我们在配置前端控制器的时候,设置的路径为“/”,表示除了jsp的访问都可以进入前端控制器。所以将发布路径后的“/images/1.png”当做一个请求去找对应的处理器去了,找不到当然就报404了。
如何解决这种问题呢。
5.1方式一
在spring的配置文件中加入以下配置。
<mvc:resources mapping="/images/**" location="/images/"/>
mapping对应浏览器地址栏中发布路径后的地址。
location对应项目中的目录。
5.2方式二
如果使用DispatcherServlet,那么tomcat的DefaultServlet就失效了。
但如果想使用tomcat默认servlet来处理静态资源在spring的配置文件中加入以下配置即可。
<mvc:default-servlet-handler/>
5.3方式三
在前端控制器的过滤配置中,改为以下配置。
<servlet>
<servlet-name>springMvc</servlet-name>
<!--前端控制器-->
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数 将spring-mvc.xml加载-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value><!--不写的话默认加载springMvc-servlet.xml-->
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springMvc</servlet-name>
<!--
/* 代表所有请求都可以进入前端控制器
/ 代表所有请求都可以进入前端控制器 不包含jsp
*.do 代表以.do的请求可以进入前端控制器
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
但是这样的话,我们需要将请求全部改为以.do结尾,不然就无法进入前端控制器找方法。
6.关于json的传递
无法使用对象接收json,也无法将json对象返回到浏览器(因为视图解析器的原因)。
@RequestBody 用于接收前端传递的请求体中的json数据, 并可以自动转换封装进指定的对象中。在接收参数的参数类型前加上此注解。
@ResponseBody将响应的内容转成json并响应浏览器。在方法上添加此注解。
7.异常处理
7.1自定义异常处理器
- 自定义异常处理器实现HandlerExceptionResolver接口,实现方法。
- 并将自定义异常处理器类加入IOC容器即可。
7.2@ControllerAdvice
- 自定义一个类,无需实现方法。
- 自定义一个处理异常的方法,并在方法上添加@ExceptionHandler注解。
- 在类上添加@ControllerAdvice注解。
- 并且要让spring的包扫描扫到这个类即可。
7.3web.xml
在web.xml中配置错误跳转页面。
8.拦截器
Spring MVC 的拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。作用:在访问到一个方法时做判断,是否要进入这个方法。
8.1执行流程:
只有在经过springMvc的前端控制器的请求才会触发拦截器。
1.preHandle:在请求进入controller之前进行拦截。
2.postHandle:controller(处理器)响应给前端控制器时拦截。
3.afterCompletion:在页面进行渲染之后进行拦截。
8.2开发步骤:
- 自定义一个拦截器,需要实现HandlerInterceptor接口。
- 重写其中的方法,包括preHandle,postHandle,afterCompletion。
- 如果在preHandle中返回false,则请求被拦截,无法想后续流程走。如果返回true,则会继续流程。
- 在spring的配置文件中,配置拦截器需要拦截的目标,格式如下:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/user/**"/><!--需要拦截的请求-->
<bean class="com.study.interceptor.LoginInterceptor"/><!--自定义的拦截器-->
</mvc:interceptor>
</mvc:interceptors>
8.3拦截器链
开发中拦截器可以单独使用,也可以同时使用多个拦截器形成一条拦截器链。
开发步骤和单个拦截器是一样的,只不过注册的时候注册多个,注册的顺序就代表拦截器执行的顺序。