213、SpringMVC学习笔记(七)【文件与拦截器】2019.09.20

17 篇文章 0 订阅

1、SpringMVC文件上传

1.1 文件上传jar包准备

与Servlet、Struts2文件上传一样,我们需要准备上传jar包

 <!--文件上传依赖的两个jar包-->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.3.3</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>

1.2 springmvc.xml配置

SpringMVC中文件上传使用的是CommonsMultipartResolver,所以我们需要将该类注入到Spring容器

 <!--注意:ID不能改变,是固定值,原因是Spring容器直接查找该固定的ID将其加入容器-->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--上传单个文件的最大值:字节,如果为-1,则表示无限制 -->
        <property name="maxUploadSize" value="17367648787"></property>
        <!-- 上传文件的编码 -->
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>

1.3 JSP表单提交

需要注意的依旧是enctype=“multipart/form-data”

<form action="/springmvc06/file/upload" method="post" enctype="multipart/form-data">
    文件:
    <input type="file" name="file">
    <br>
    描述
    <input type="text" name="desc" value="">
    <button name="btn">文件上传</button>
</form>

1.4 Controller对应的处理

@Controller
@RequestMapping("/file")
public class FileController {

    @RequestMapping("upload")
    public String upload(@RequestParam String desc ,
                         @RequestParam("file") MultipartFile file){

        String storePath = "F:\\work\\testjava";
        String fileName = file.getOriginalFilename();
        File filePath = new File(storePath , fileName);
        if (!filePath.getParentFile().exists()) {
            // 如果目录不存在,则创建目录
            filePath.getParentFile().mkdirs();
        }
        try {
            file.transferTo(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "success";
    }
}

1.5 大小限制测试

2、SpringMVC文件下载

@RequestMapping("download")
    public ResponseEntity<byte[]> download() throws IOException {
        //文件获取,替换成数据库查询出的路径
        String fileName = "张三.png";
        String filePath = "F:\\work\\testjava";
        File file = new File(filePath , fileName);

        //文件乱码解决
        String dfileName = new String(fileName.getBytes("utf-8"), "iso8859-1");

        //请求头设置
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentDispositionFormData("attachment", fileName);

        //将文件转化为字节数组
        byte[] bytes = FileUtils.readFileToByteArray(file);
        return new ResponseEntity<byte[]>(bytes , headers, HttpStatus.CREATED);
    }

2.1 JSP

<a href="/springmvc06/file/download">下载</a>

3、异常处理

在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

3.1 处理流程

在这里插入图片描述

3.2 传统的异常处理

在开发中,不管是dao层、service层还是controller层,都有可能抛出异常,在springmvc中,能将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单一,也实现了异常信息的统一处理和维护。

@Repository
public class UserDao {

    public Map<String,Object> getUser(){
        return null;
    }
}

@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public Map<String,Object> getUser() throws Exception {
        //大量的代码片段
        try {
            System.out.println(10/0);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("查询用户订单信息失败");
        }
        return null;
    }
}

@Controller
@RequestMapping("user")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping("getUser")
    public ModelAndView getUser() {
        ModelAndView mav = new ModelAndView("user");
        Map<String, Object> user = null;
        try {
            user = userService.getUser();
            mav.addObject("user" , user);
            mav.addObject("success" , true);
        } catch (Exception e) {
            e.printStackTrace();
            mav.addObject("success" , false);
            mav.addObject("errMsg" , e.getMessage());
        }
        return mav;
    }
}

4、异常处理实现

在SpringMVC中,所有的异常处理类,都实现了HandlerExceptionResolver接口,该接口为异常顶级接口,其下的每个实现类,都是每种异常处理的实现方式,如:ExceptionHandlerExceptionResolver、SimpleMappingExceptionResolver等。若需要自定义全局的异常处理器,需要实现该接口。

ExceptionHandlerExceptionResolver:接口主要提供了,@ExceptionHandler

4.1 @ExceptionHandler

统一处理某一类异常,从而能够减少代码重复率和复杂度。@ExceptionHandler修饰的方法参数必须是异常类型(Throwable或其子类),不能包含其他类型参数

(1)单异常捕获

    /**
     * 出现算术异常
     * @return
     */
    @RequestMapping("arithmetic")
    public String arithmetic(){
        System.out.println(1/0);
        return "success";
    }

    @ExceptionHandler({ArithmeticException.class})
    public ModelAndView handlerException(ArithmeticException e){
        System.out.println(e + ":异常信息打印");
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("errorObj", e);
        return mav;
    }

(2)多个异常捕获
若存在多个@ExceptionHandler,其捕获规则仍然和异常的范围大小进行,最大的范围为Exception,与多catch类似

    /**
     * 出现算术异常
     * @return
     */
    @RequestMapping("arithmetic")
    public String arithmetic(){
        System.out.println(1/0);
        return "success";
    }

    /**
     * 出现下标越界异常
     * @return
     */
    @RequestMapping("arrayIndexOut")
    public String download() {
        int[] is = new int[2];
        System.out.println(is[3]);
        return "success";
    }

    /**
     * 该方法可以捕获当前类中的多个异常
     */
    @ExceptionHandler({ArithmeticException.class , ArrayIndexOutOfBoundsException.class})
    public ModelAndView handlerException(Exception e){
        System.out.println(e + ":异常信息打印");
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("errorObj", e);
        return mav;
    }

(3)修饰方法的返回值类型

  • ModelAndView对象
  • Model对象
  • Map对象
  • View对象
  • String对象
  • 还有@ResponseBody、HttpEntity<?>或ResponseEntity<?>,以及void

(4)缺点

  • 代码有侵入性,处理情况复杂
  • 进行异常处理的方法必须与出错的方法在同一个Controller里面

4.2 @ControllerAdvice

该注解为控制器增强,修饰对象包括类、接口和枚举等,在运行时有效,并且可以通过Spring扫描为bean组件。其可以包含由@ExceptionHandler、@InitBinder 和@ModelAttribute标注的方法,可以处理多个Controller类,这样所有控制器的异常可以在一个地方进行处理,被用作全局的异常捕捉。

ExceptionHandlerMethodResolver如果在当前Handler中找不到@ExceptionHandler方法来处理当前方法出现的异常, 则将去@ControllerAdvice标记的类中查找@ExceptionHandler标记的方法来处理异常。
用法

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ModelAndView handleException(Exception ex){
        System.out.println("异常:"+ ex);
        ModelAndView mv = new ModelAndView("error");
        mv.addObject("exception",ex);
        return mv;
    }
}

全局异常案例

(1)自定义运行异常

public class CustomException extends RuntimeException{

    private String errCode;

    private String errMsg;

    public CustomException(String errMsg, String errCode) {
        this.errCode = errCode;
        this.errMsg = errMsg;
    }
}

(2)定义全局的异常处理类

package com.hliedu.controller.exception;

import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有自定义的业务异常
     * @param e
     * @return
     */
    @ExceptionHandler(CustomException.class)
    public ModelAndView customExceptionHnadler(CustomException e){
        ModelAndView mav = new ModelAndView("custom_error");
        mav.addObject("errCode",e.getErrCode());
        mav.addObject("errMsg",e.getErrMsg());
        return mav;
    }

    /**
     * 处理所有未知的异常
     * @param exception
     * @return
     */
    @ExceptionHandler(Exception.class)
    public ModelAndView allExceptionHandler(Exception exception){
        ModelAndView mav = new ModelAndView("all_error");
        mav.addObject("errMsg", "this is Exception.class");
        return mav;
    }
}

(3)模拟异常控制器

@Controller
@RequestMapping("exception")
public class ExceptionController {

    @RequestMapping("all")
    public String all(){
        //将会被GlobalExceptionHandler.allExceptionHandler方法捕获
        System.out.println(10/0);
        return "success";
    }

    @RequestMapping("custom")
    public String custom(){
        if(true){
            //将会被GlobalExceptionHandler.customExceptionHnadler方法捕获
            throw new CustomException("异常" , "-1");
        }
        return "success";
    }
}

(4)拓展

  • @ExceptionHandler和@ControllerAdvice能够集中异常,使异常处理与业务逻辑分离
  • 除了返回ModelAndView界面,还可以以@ResponseBody的形式响应给客户端
  • @ControllerAdvice支持界面、异步响应的方式
  • @RestControllerAdvice为REST变种异常增强,可参考@RestController

5、拦截器

拦截器是指访问某个Handler或Handler的方法之前或之后实施拦截,它提供了一种机制可以使开发者可以定义在一个Handler执行的前后执行的代码,也可以在一个Handler执行前阻止其执行。同时也是提供了一种可以提取Handler中可重用的部分代码的方式。 并且拦截器是可插拔的,拦截器是面向切面(AOP)的一种体现,如CGLIB正是采用的拦截器的做法实现。

拦截器栈(Interceptor Satck):拦截器栈就是将拦截器按一定的顺序连接成一条链。在访问被拦截的方法或字段时,拦截器栈中的拦截器就会按其之前定义的顺序被调用,栈结构为先进后出
在这里插入图片描述
SpringMVC也可以使用拦截器对请求进行拦截处理,用户可以自定义拦截器来实现特定的功能,自定义的拦截器必须实现HandlerInterceptor接口

5.1 HandlerInterceptor接口描述

boolean preHandle(request, response, Object handler) throws Exception;

void postHandle(request,response,Object handler,modelAndView) throws Exception;

void afterCompletion(request,response,Object handler,Exception ex)throws Exception;
  • preHandle():在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理。需要开发人员提供一个boolean类型的返回值。
    • 返回true:表示继续执行其他拦截器或handler方法
    • 返回false:表示中断执行,后续等待的拦截器或handler方法不再执行
  • postHandle():在业务处理器处理请求执行完成后,生成视图之前执行(页面未渲染)。
  • afterCompletion():在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。

5.2 拦截器配置

<mvc:interceptors>
    <!--该拦截器,拦截所有的请求-->
    <bean id="allInterceptor" class="com.hliedu.interceptor.AllInterceptor"/>

    <!--该拦截器拦截指定mapping的请求-->
    <mvc:interceptor>
        <!--需要拦截的地址,通配符形式-->
        <mvc:mapping path="/web/**"/>
        <!--不执行拦截某个地址-->
        <mvc:exclude-mapping path="/web/login"/>
        <bean id="webInterceptor"  class="com.hliedu.interceptor.WebInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

6、拦截器的使用

6.1 定义拦截器

java package com.hliedu.test.interceptor;

import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       System.out.println("在handler处理器之前调用");
       //返回值如果是true,表示继续执行拦截器或handler处理方法
       return true;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       //渲染:界面数据绑定,界面的产生
       request.setAttribute("inter" ,"inter");
       System.out.println("在handler处理方法之后,渲染界面之前执行");
   }

   @Override
   public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
       System.out.println("所有功能都执行完成之后执行");
   }
}

6.2 定义handler方法

   java package com.hliedu.test.controller;
   import com.hliedu.test.exception.CustomException;
   import com.hliedu.test.service.UserService;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.stereotype.Controller;
   import org.springframework.web.bind.annotation.RequestMapping;
   import org.springframework.web.servlet.ModelAndView;
   import java.util.Map;
   
   @Controller
   @RequestMapping("inter")
   public class InterceptController {

       /**
        * MyInterceptor拦截器将对该方法进行拦截
        * @return
        */
       @RequestMapping("test1")
       public String test1() {
           System.out.println("test1方法执行");
           return "success";
       }

       /**
        * 该方法在springmvc.xml中配置的不拦截
        * @return
        */
       @RequestMapping("test2")
       public String test2() {
           System.out.println("test2方法执行");
           return "success";
       }
   }

6.3 配置拦截器

<!--声明拦截器-->
        <mvc:interceptors>
            <mvc:interceptor>
                <!--拦截指定的映射路径-->
                <mvc:mapping path="/inter/**"/>
                <!--排除拦截路径-->
                <mvc:exclude-mapping path="/inter/test2"/>
                <bean class="com.hliedu.test.interceptor.MyInterceptor"/>
            </mvc:interceptor>
        </mvc:interceptors>

7、拦截器登录功能实现

需求:用户需要登录后才能进入用户中心,否则将直接回到登录界面

关键点:session

7.1 登录界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录界面</title>
</head>
<body>

<h2>登录界面</h2>
    <a href="/springmvc06/user/login">点击登录</a>
</body>
</html>

7.2 用户中心界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户中心</title>
</head>
<body>

    <h2>用户中心</h2>
</body>
</html>

7.3 登录与用户中心handler

package com.hliedu.test.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import javax.servlet.http.HttpServletRequest;

@Controller
@RequestMapping("user")
@SessionAttributes("USER_LOGIN")
public class LoginController {

    @RequestMapping("login")
    public String login(ModelMap modelMap) {
        modelMap.addAttribute("USER_LOGIN" , true);
        System.out.println("用户登录");
        return "user/center";
    }

    @RequestMapping("center")
    public String center() {
        System.out.println("进入用户中心");
        return "user/center";
    }
}

7.4 登录拦截器

java package com.hliedu.test.interceptor;

import org.springframework.web.servlet.HandlerInterceptor; 
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession;

public class LoginInterceptor implements HandlerInterceptor {

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       HttpSession session = request.getSession();
       Object user_login = session.getAttribute("USER_LOGIN");
       System.out.println(user_login);
       if(user_login == null){
           System.out.println("未登录");
           request.getRequestDispatcher("/user/login").forward(request,response);
           return false;
       }
       return true;
   }

   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
       //渲染:界面数据绑定,界面的产生
       System.out.println("在handler处理方法之后,渲染界面之前执行");
   }
} ```

8、参考链接

【01】文件与拦截
【02】SpringMVC实现文件下载的两种方式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值