SpringMVC补充文件上传下载,异常与拦截
1 文件上传
1.1 jsp
- post提交
- file文件域
- enctype=mutipart/form-data
<form action="<c:url value='/test01/upload.action'/>" method="post" enctype="multipart/form-data">
<table>
<tr>
<th>name:</th>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<th>sex:</th>
<td><input type="text" name="sex"/></td>
</tr>
<tr>
<th>file:</th>
<td><input type="file" name="photo_file"/></td>
</tr>
<tr>
<th>age:</th>
<td><input type="text" name="age"/></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="文件上传"/>
</th>
</tr>
</table>
</form>
1.2 action
-
MultiPartFile来接受文件域组件
-
对象的属性名一定不要和文件域的name相同
@Controller
@RequestMapping("/test01")
public class Test01 {
@RequestMapping("/upload.action")
public String uplaodMethod(Student stu,@RequestParam("photo_file") MultipartFile file)throws Exception{
//System.out.println("getOriginalFilename="+file.getOriginalFilename());//文件名字
//System.out.println("getName="+file.getName());//组件名字
//System.out.println("getSize="+file.getSize());//文件大小
//System.out.println("getContentType="+file.getContentType());//文件类型
//System.out.println("getInputStream="+file.getInputStream());//获取文件的输入流
//System.out.println("getBytes="+file.getBytes());//获取文件的字节
//System.out.println("transferTo="+file.transferTo(File);); //文件复制
//获取文件名字
String fileName=file.getOriginalFilename();
//创建目的文件
File fileMuDi=new File("e:/imgs_uplaod",System.currentTimeMillis()+"_"+fileName);
System.out.println(fileMuDi.getAbsolutePath());
//实现文件的复制
file.transferTo(fileMuDi);
stu.setPhoto(fileMuDi.getName());
return "test01_sucess";
}
}
2 文件下载
2.1 在web.xml中指定文件下载的源文件夹
<!-- 定义项目初始化参数 指定文件下载的目录 -->
<context-param>
<param-name>download_path</param-name>
<param-value>/imgs</param-value>
</context-param>
2.2 jsp提供超链接 指定文件名即可
<h1>文件下载</h1>
<a href="<c:url value='/test02/download.action?fileName=11.jpg'/>">下载11.jpg</a><br/>
<a href="<c:url value='/test02/download.action?fileName=12.jpg'/>">下载12.jpg</a><br/>
<a href="<c:url value='/test02/download.action?fileName=13.jpg'/>">下载13.jpg</a><br/>
<a href="<c:url value='/test02/download.action?fileName=14.jpg'/>">下载14.jpg</a><br/>
<a href="<c:url value='/test02/download.action?fileName=换行.jpg'/>">下载换行.jpg</a><br/>
2.3 action
- 设置响应头 指定响应内容的类型
- 设置响应头 指定客户端以附件形式保存
- 返回值类型是ResponseEntity<byte[]>
@Controller
@RequestMapping("/test02")
public class Test02 {
@RequestMapping("/download.action")
public ResponseEntity<byte[]> downloadMethod(String fileName,HttpServletRequest req)throws Exception{
//获取文件的类型
String type=req.getServletContext().getMimeType(fileName);
//获取web.xml中配置的初始化参数:download_path
String path=req.getServletContext().getInitParameter("download_path");// /imgs
//获取真实路径
String realPath=req.getServletContext().getRealPath(path);
File yuanFile=new File(realPath,fileName);
// byte[] arr=new byte[(int)yuanFile.length()];
// FileInputStream fin=new FileInputStream(yuanFile);
// fin.read(arr);
// fin.close();
byte[] arr=FileUtils.readFileToByteArray(yuanFile);
//创建heander对象 响应头
HttpHeaders headers=new HttpHeaders();
headers.set("Content-Type", type);
headers.set("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName, "utf-8"));
//获取源文件
//context.get
ResponseEntity<byte[]> entity=new ResponseEntity<byte[]>(arr,headers,HttpStatus.OK);
return entity;
}
}
3 异常处理
3.1 自定义异常
public class UserLoginException extends RuntimeException{
public UserLoginException(String message){
super(message);
}
}
public class UserNameException extends RuntimeException{
public UserNameException(String message){
super(message);
}
}
public class UserPwdException extends RuntimeException{
public UserPwdException(String message){
super(message);
}
}
3.2 定义处理异常的通知类
- 实现接口HandlerExceptionResolver
- 添加注解@Component
- 在resolveException方法中对不同异常进行选择处理
@Component
public class MyExceptionAdvice implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2,
Exception e) {
ModelAndView mv=new ModelAndView();
mv.addObject("message", e.getMessage());
mv.addObject("exception2", e);
mv.setViewName("test03_error");
if(e instanceof UserLoginException){
mv.addObject("status","5001");
}
if(e instanceof UserNameException){
mv.addObject("status","4001");
}
if(e instanceof UserPwdException){
mv.addObject("status","4002");
}
return mv;
}
}
3.3 创建抛出异常的action和service
- service
@Service
public class Test21Service {
public boolean login(String name,String pwd){
if(name.length()>4){
throw new UserNameException("用户名长度错误!");
}else if(!pwd.equals("123456")){
throw new UserPwdException("用户密码错误!");
}
return true;
}
}
- action
@Controller
@RequestMapping("/test21")
public class Test21 {
@Autowired
private Test21Service test21Service;
@RequestMapping("/login.action")
public String loginMethhod(String name,String pwd,Model m){
boolean b=test21Service.login(name, pwd);
if(!name.matches("^[\u4e00-\u9fa5]{2,4}$")){
throw new UserLoginException("用户名必须是2到4个汉字");
}
m.addAttribute("name", name);
m.addAttribute("pwd", pwd);
return "test03_success";
}
}
3.4 请求页面 和 错误页面
- test03.jsp
<h1>异常处理:登录表单</h1>
<form action="<c:url value='/test21/login.action'/>" method="post">
<table>
<tr>
<th>name:</th>
<td><input type="text" name="name"/></td>
</tr>
<tr>
<th>pwd:</th>
<td><input type="text" name="pwd"/></td>
</tr>
<tr>
<th colspan="2">
<input type="submit" value="用户登录"/>
</th>
</tr>
</table>
</form>
- test03_error.jsp
exception=${exception}<br/>
exception2=${exception2}<br/>
message=${message }<br/>
status=${status }<br/>
3.5 spring3.2以后处理异常
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(UserLoginException.class)
public String handleException(Exception e){
...
return "test03_error";
}
@ExceptionHandler(UserNameException.class)
public String handleException(Exception e){
...
return "test03_error";
}
}
4 拦截器Interceptor
4.1 概念
* 拦截器:interceptor
* springmvc中定义的类似于filter的组件 用于对指定的action进行拦截 拦截后可以选择放行
* 而且在action之前和之后添加代码
* 作用:异常处理 权限控制 日志管理 资源释放 等..
4.2 案例
- 创建action
@Controller
@RequestMapping("/test31")
public class Test31 {
@RequestMapping("/m1.action")
public String method01(int age,String name,Model m){
System.out.println(age+":"+name);
m.addAttribute("name", name);
m.addAttribute("age", age);
m.addAttribute("message", "method01");
return "test04";
}
@RequestMapping("/m2.action")
public String method02(int age,String name,Model m){
System.out.println(age+":"+name);
m.addAttribute("name", name);
m.addAttribute("age", age);
m.addAttribute("message", "method0122222");
return "test04";
}
}
- 创建jsp
<h1>拦截器</h1>
<c:if test="${not empty message}">
message=${message}<br/>
</c:if>
<c:if test="${not empty age}">
age=${age}<br/>
</c:if>
<c:if test="${not empty name}">
name=${name}<br/>
</c:if>
<a href="<c:url value='/test31/m1.action?age=111&name=韩梅梅1'/>">请求/test31/m1.action</a><br/>
<a href="<c:url value='/test31/m2.action?age=112&name=韩梅梅2'/>">请求/test31/m2.action</a><br/>
<a href="<c:url value='/test31/m3.action?age=113&name=韩梅梅3'/>">请求/test31/m3.action</a><br/>
- 创建拦截器:实现接口HandlerInceptor
public class Test31Interceptor01 implements HandlerInterceptor{
//afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("afterCompletion====");
}
//postHandle:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("postHandle===age="+arg3.getModel().get("age"));
System.out.println("postHandle===name="+arg3.getModel().get("name"));
arg3.addObject("age", (Integer)arg3.getModel().get("age")+1);
}
// preHandle:进行预处理的代码:在action执行之前执行的代码::权限控制。。请求参数转换验证。。
// 返回true 放行 返回false 不放行
public boolean preHandle(HttpServletRequest req, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("preHandle===arg2="+arg2.getClass());//arg2参数是当前action方法对象
System.out.println("preHandle===请求的url="+req.getServletPath());
return true;
}
}
- 在核心配置文件中通过mvc标签配置拦截器
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/test31/*"/>
<!-- <mvc:exclude-mapping path="/test31/m1.action"/>指定不拦截的action:此标签适用于4.+以上的版本-->
<bean class="com.zhiyou100.test03_interceptor.Test31Interceptor01"/>
</mvc:interceptor>
</mvc:interceptors>
- 验证 略
4.3 拦截器和过滤器的区别
- 概念
拦截器interceptor:springmvc中对指定action进行拦截 选择放行 并且在action执行前后可以加代码的组件
过滤器filter:javaweb三大组件之一 由web容器创建、维护和销毁的组件 可以对web资源进行拦截 选择放行 并且在资源处理请求之前和之后添加代码
- 相同之处
都可以拦截对action请求
都可以在请求前后添加代码
功能基本一致
- 不同之处
1 实现接口不同
过滤器实现接口:javax.servlet.Filter
拦截器实现接口:org.springframework.web.servlet.HandlerInterceptor
2 是否依赖web容器
filter依赖web容器 需要tomcat创建、调用和销毁:只适用于web项目
interceptor不依赖web容器 适用于所有项目 只需要导入拦截器依赖的jar即可
3 拦截的资源不同
filter可以拦截所有资源:html action css servlet img
interceptor只能拦截action
4 原理不同
filter原理是方法回调
interceptor原理是反射和动态代理