• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
在赶路的我
博客园    首页    新随笔    联系   管理    订阅  订阅

SpringMVC的高级用法

springmvc的高级用法

springmvc对于异常的处理

问题及解决

在程序的开发中,或多或上都会出现一些异常,如果每一个异常都进行单独的处理,那么程序将会出现大量的冗余代码并且代码规范性差,不易于后续代码的维护。如果将程序中所有的异常都抽取出来做统一的处理,即可以实现将所有的异常作统一的处理,也避免了代码的冗余。
在SpringMVC中三种解决方法1.使用简单的异常处理类SimpleMappingExceptionResolver 2.实现HandlerExceptionResolver接口自定义异常处理器 3.使用@ControllerAdvice和@ExceptionHandler注解实现和自定义异常处理的效果

异常处理(HandlerExceptionResolver接口)

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerExceptionResolver {
    @Nullable
    ModelAndView resolveException(HttpServletRequest var1, HttpServletResponse var2, @Nullable Object var3, Exception var4);
	//var4是出现的异常类型
}

对于简单的异常处理(使用SimpleMappingsExceptionResolver)

package org.springframework.web.servlet.handler;

import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.WebUtils;

public class SimpleMappingExceptionResolver extends AbstractHandlerExceptionResolver {
    public static final String DEFAULT_EXCEPTION_ATTRIBUTE = "exception";
    @Nullable
    //是存储异常和处理页面的映射关系
    private Properties exceptionMappings;
    
    @Nullable
    private Class<?>[] excludedExceptions;
    @Nullable
    //如果没有特地的设置对应关系,则使用默认的视图处理异常
    private String defaultErrorView;
    @Nullable
    private Integer defaultStatusCode;
    private Map<String, Integer> statusCodes = new HashMap();
    @Nullable
    //异常信息,跳到处理页面的时候,使用变量exception来输出异常信息
    private String exceptionAttribute = "exception";

    public SimpleMappingExceptionResolver() {
    }

    public void setExceptionMappings(Properties mappings) {
        this.exceptionMappings = mappings;
    }

    public void setExcludedExceptions(Class<?>... excludedExceptions) {
        this.excludedExceptions = excludedExceptions;
    }

    public void setDefaultErrorView(String defaultErrorView) {
        this.defaultErrorView = defaultErrorView;
    }

    public void setStatusCodes(Properties statusCodes) {
        Enumeration enumeration = statusCodes.propertyNames();

        while(enumeration.hasMoreElements()) {
            String viewName = (String)enumeration.nextElement();
            Integer statusCode = Integer.valueOf(statusCodes.getProperty(viewName));
            this.statusCodes.put(viewName, statusCode);
        }

    }

    public void addStatusCode(String viewName, int statusCode) {
        this.statusCodes.put(viewName, statusCode);
    }

    public Map<String, Integer> getStatusCodesAsMap() {
        return Collections.unmodifiableMap(this.statusCodes);
    }

    public void setDefaultStatusCode(int defaultStatusCode) {
        this.defaultStatusCode = defaultStatusCode;
    }

    public void setExceptionAttribute(@Nullable String exceptionAttribute) {
        this.exceptionAttribute = exceptionAttribute;
    }

    @Nullable
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {
        String viewName = this.determineViewName(ex, request);
        if (viewName != null) {
            Integer statusCode = this.determineStatusCode(request, viewName);
            if (statusCode != null) {
                this.applyStatusCodeIfPossible(request, response, statusCode);
            }

            return this.getModelAndView(viewName, ex, request);
        } else {
            return null;
        }
    }

    @Nullable
    protected String determineViewName(Exception ex, HttpServletRequest request) {
        String viewName = null;
        if (this.excludedExceptions != null) {
            Class[] var4 = this.excludedExceptions;
            int var5 = var4.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                Class<?> excludedEx = var4[var6];
                if (excludedEx.equals(ex.getClass())) {
                    return null;
                }
            }
        }

        if (this.exceptionMappings != null) {
            viewName = this.findMatchingViewName(this.exceptionMappings, ex);
        }

        if (viewName == null && this.defaultErrorView != null) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Resolving to default view '" + this.defaultErrorView + "'");
            }

            viewName = this.defaultErrorView;
        }

        return viewName;
    }

    @Nullable
    protected String findMatchingViewName(Properties exceptionMappings, Exception ex) {
        String viewName = null;
        String dominantMapping = null;
        int deepest = 2147483647;
        Enumeration names = exceptionMappings.propertyNames();

        while(true) {
            String exceptionMapping;
            int depth;
            do {
                do {
                    if (!names.hasMoreElements()) {
                        if (viewName != null && this.logger.isDebugEnabled()) {
                            this.logger.debug("Resolving to view '" + viewName + "' based on mapping [" + dominantMapping + "]");
                        }

                        return viewName;
                    }

                    exceptionMapping = (String)names.nextElement();
                    depth = this.getDepth(exceptionMapping, ex);
                } while(depth < 0);
            } while(depth >= deepest && (depth != deepest || dominantMapping == null || exceptionMapping.length() <= dominantMapping.length()));

            deepest = depth;
            dominantMapping = exceptionMapping;
            viewName = exceptionMappings.getProperty(exceptionMapping);
        }
    }

    protected int getDepth(String exceptionMapping, Exception ex) {
        return this.getDepth(exceptionMapping, ex.getClass(), 0);
    }

    private int getDepth(String exceptionMapping, Class<?> exceptionClass, int depth) {
        if (exceptionClass.getName().contains(exceptionMapping)) {
            return depth;
        } else {
            return exceptionClass == Throwable.class ? -1 : this.getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
        }
    }

    @Nullable
    protected Integer determineStatusCode(HttpServletRequest request, String viewName) {
        return this.statusCodes.containsKey(viewName) ? (Integer)this.statusCodes.get(viewName) : this.defaultStatusCode;
    }

    protected void applyStatusCodeIfPossible(HttpServletRequest request, HttpServletResponse response, int statusCode) {
        if (!WebUtils.isIncludeRequest(request)) {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Applying HTTP status " + statusCode);
            }

            response.setStatus(statusCode);
            request.setAttribute("javax.servlet.error.status_code", statusCode);
        }

    }

    protected ModelAndView getModelAndView(String viewName, Exception ex, HttpServletRequest request) {
        return this.getModelAndView(viewName, ex);
    }

    protected ModelAndView getModelAndView(String viewName, Exception ex) {
        ModelAndView mv = new ModelAndView(viewName);
        if (this.exceptionAttribute != null) {
            mv.addObject(this.exceptionAttribute, ex);
        }

        return mv;
    }
}

测试:

//需要注册SimpleMappingExceptionResolver
//当然可以对其中的属性进行设置
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            //key是异常的类名或者完整类名;value是对应处理异常的页面
            //页面是在模板引擎指定的路径下找
            <prop key="java.lang.NullPointerException">NullPointerException.html</prop>
        </props>
    </property>
</bean>
//空指针异常
@RequestMapping("/null")
public void nullException(){
    ArrayList<Object> objects = null;
    System.out.println(objects.get(3));
}
//请求这个有空指针异常的请求会跳到对应的页面进行处理

自定义异常处理器(实现HandlerExceptionResovler)

  1. 实现HandlerExceptionResolver接口

    • package com.chen.handlerexception;
      
      import com.chen.exception.MyException;
      import org.springframework.web.servlet.HandlerExceptionResolver;
      import org.springframework.web.servlet.ModelAndView;
      
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      
      public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
          @Override
          public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
      
              //自定义一个处理空指针的异常处理类
              ModelAndView mv = new ModelAndView();
      
              String msg = null;
      
              if (e instanceof MyException){
      
                  msg = e.getMessage();
                  mv.addObject("msg",msg);
              }else{
                  msg = "其他异常";
                  mv.addObject("msg",msg);
              }
      
              mv.setViewName("NullPointerException");
      
      
              return mv;
      
      
          }
      }
      
      
  2. 自定义异常MyException

    • package com.chen.exception;
      
      public class MyException extends Exception{
      
          String exceptionMsg = null;
      
          public MyException(String message) {
              super(message);
              this.exceptionMsg=message;
          }
      
          @Override
          public String getMessage() {
              return this.exceptionMsg;
          }
      }
      
      
  3. 注册自定义的异常处理器

    • <bean class="com.chen.handlerexception.MyHandlerExceptionResolver"/>
      
  4. 测试

    • //自定义异常
      //异常一定要往外抛,让springmvc的异常处理器发现
      @RequestMapping("/null")
      public void nullException() throws MyException {
          throw new  MyException("空指针异常");
      }
      

注解版的异常处理(利用@ControllerAdvice来为每一个请求处理方法增加逻辑处理)(这个于自定义异常处理器一样)

  1. 定义异常处理的处理方法

    • package com.chen.mycontrolleradvice;
      
      
      import com.chen.exception.MyException;
      import org.springframework.web.bind.annotation.ControllerAdvice;
      import org.springframework.web.bind.annotation.ExceptionHandler;
      import org.springframework.web.servlet.ModelAndView;
      
      @ControllerAdvice
      //@ControllerAdvice用于在有@RequestMapping注解标注的处理方法添加逻辑处理
      public class MyControllerAdvice {
          //用于处理MyException的异常
          //@ExceptionHandler注解用于告诉处理什么样的异常
          @ExceptionHandler(MyException.class)
          public ModelAndView myException(MyException myException){
      
              ModelAndView mv = new ModelAndView();
      
              System.out.println(myException.getMessage());
      
              mv.addObject("msg",myException.getMessage());
      
              mv.setViewName("NullPointerException");
      
              return mv;
          }
          
      }
      
      
    • 测试

      • //注解版自定义异常
        @RequestMapping("/null")
        public void nullException() throws MyException {
            throw new  MyException("注解版空指针异常");
        }
        

关于@ControllerAdvice的详解

@ControllerAdvice是spring3.2之后出现的注解
作用:
	1.为Controller中的每一个被@RequestMapping标注的处理方法添加一些逻辑处理
	2.结合@ExceptionHandler使用,可以捕获Controller中指定类型的异常并进行处理,从而实现不同异常的统一处理

拦截器

概述:

拦截器是一种动态拦截Controller方法调用的对象,他可以在方法被调用前和调用后执行预先设置好的代码

作用:

1.可以拦截未登录的用户
2.对已经登录的用户进行操作权限的限制

定义拦截器(springmvc中提供了两种方式)

  1. 实现HandlerInterceptor:需要实现所有的方法(但是在default关键词出现后,实现需要实现的方法)
  2. 实现HandlerInterceptorAdapter:可以只实现需要回调的方法(这种方法已过时)

HandlerInterceptor接口

package org.springframework.web.servlet;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.lang.Nullable;

public interface HandlerInterceptor {
    /**
    用于对程序进行安全控制,权限验证。在调用Controller中的处理方法之前被调用
    第三个参数handler表示被调用的那个处理方法的封装对象
    返回值为布尔值: true,继续向下执行;false,中断请求(包括调用下一个拦截器或者处理方法)
    */
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
	/**
	在处理方法被调用之后执行
	第三个参数为ModelAndView,可以在这里读取或者调整返回到客户端的数据
	*/
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
	/**
	在这个请求结束,即在视图渲染结束之后被调用
	常常在这里完成资源清理,日志信息记录等工作
	第三个参数为在处理方法执行过程中的异常,也可以在这里对异常进行单独处理
	*/
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

自定义登录拦截器

package com.chen.MyInterceptor;

import com.chen.pojo.User;
import org.springframework.lang.Nullable;
import org.springframework.web.method.HandlerMethod;
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();

        //在这里需要单独给user捕获空指针异常,否则直接在页面报错程序直接停止
        try {
            User user = (User) session.getAttribute("user");
            if (user.getUsername().trim().equals("陈浪涛")&&user.getPassword().equals("123")){
                return true;
            }
        }catch (NullPointerException e){
            System.out.println(e.getStackTrace());
            System.out.println(e.getMessage());
        }

        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().print("你还没有登录");

        return false;

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

注册拦截器

<!--配置拦截器方式一-->
<mvc:interceptors>
    <!--可以配置拦截路径和不拦截的路径-->
    <mvc:interceptor>
        <!--在这里注意以下的顺序不能打乱,否则报错-->
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/login"/>
        <bean class="com.chen.MyInterceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
<!--配置拦截器方式二-->
<mvc:interceptors>
    <!--直接配置bean代表拦截所有的请求-->
    <bean class="com.chen.MyInterceptor.LoginInterceptor2"/>
</mvc:interceptors>

测试

  • 自定义的登录拦截器

    • package com.chen.MyInterceptor;
      
      import com.chen.pojo.User;
      import org.springframework.lang.Nullable;
      import org.springframework.web.method.HandlerMethod;
      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();
      
              //在这里需要单独给user捕获空指针异常,否则直接在页面报错程序直接停止
              try {
                  User user = (User) session.getAttribute("user");
                  if (user.getUsername().trim().equals("陈浪涛")&&user.getPassword().equals("123")){
                      return true;
                  }
              }catch (NullPointerException e){
                  System.out.println(e.getStackTrace());
                  System.out.println(e.getMessage());
              }
      
              response.setContentType("text/html;charset=UTF-8");
              response.getWriter().print("你还没有登录");
      
              return false;
      
          }
      
          @Override
          public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
              HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
          }
      
          @Override
          public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
              HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
          }
      }
      
      
  • 测试处理方法

    • @RequestMapping("/login")
      public String login(@Nullable String username,@Nullable String password, HttpServletRequest request){
      
          HttpSession session = request.getSession();
          User user = new User(username,password);
          session.setAttribute("user",user);
      
          return "forward:/index";
      }
      
      @RequestMapping("/index")
      public String toIndex(){
          return "index";
      }
      

单个拦截器的执行流程

多个拦截器执行流程

拦截器和过滤器的区别

  • 拦截器:
    • 使用springmvc技术
    • 拦截的是SpringMVC中的Controller中的处理方法
  • 过滤器:
    • 使用servlet技术
    • 对每一个请求都过滤

文件上传与下载

文件上传

  1. 依赖

    • <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
      <dependency>
          <groupId>commons-fileupload</groupId>
          <artifactId>commons-fileupload</artifactId>
          <version>1.3</version>
      </dependency>
      <!--在这里fileupload会依赖commonsio所以不用在单独导入commonsio的包-->
      
  2. 注入springmvc提供的文件解析器CommonsMultipartResolver

    • <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
      <!--beanFactory会寻找id为multipartResolver的bean所以id必须为这个id-->
      
  3. 测试

    • //单文件上传
      @RequestMapping("/uploadFile")
      @ResponseBody
      public String uploadFile(MultipartFile file){
      
          String fileName = null;
      
          if (!file.isEmpty()){
              fileName = file.getOriginalFilename();
          }
      
          fileName = fileName + "上传成功";
      
          return fileName;
      }
      

多文件上传

文件下载

  • 文件下载的方式一(可以实现下载功能)
//文件下载
@RequestMapping("/download")
public void download(HttpServletRequest request,HttpServletResponse response,String fileName) throws IOException{
    File file = new File("D:\\java-workspace-idea\\DataBinder\\src\\main\\resources",fileName);

    FileInputStream is = new FileInputStream(file);
    // 3. 获取响应输出流
    response.setContentType("text/plain;charset=UTF-8");
    // 4. 附件下载 attachment 附件 inline 在线打开(默认值)
    response.setHeader("content-disposition", "attachment;fileName=" + fileName);
    // 5. 处理下载流复制
    ServletOutputStream os = response.getOutputStream();
    int len;
    byte[] buffer = new byte[1024];
    while((len=is.read(buffer))!=-1){
        os.write(buffer, 0, len);
    }
    // 释放资源
    os.close();
    is.close();
}
  • 文件下载的方式二(会报错,目前没有解决)
@RequestMapping("/testDown")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws
    IOException {
    //获取ServletContext对象
    ServletContext servletContext = session.getServletContext();
    //获取服务器中文件的真实路径
    String realPath = servletContext.getRealPath("/static/img/1.jpg");
    //创建输入流
    InputStream is = new FileInputStream(realPath);
    //创建字节数组
    byte[] bytes = new byte[is.available()];
    //将流读到字节数组中
    is.read(bytes);
    //创建HttpHeaders对象设置响应头信息
    MultiValueMap<String, String> headers = new HttpHeaders();
    //设置要下载方式以及下载文件的名字
    headers.add("Content-Disposition", "attachment;filename=1.jpg");
    //设置响应状态码
    HttpStatus statusCode = HttpStatus.OK;
    //创建ResponseEntity对象
    ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers,statusCode);
    //关闭输入流
    is.close();
    return responseEntity;
}

posted @ 2023-08-03 22:06  在赶路的我  阅读(37)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3