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)
-
实现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; } }
-
-
自定义异常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; } }
-
-
注册自定义的异常处理器
-
<bean class="com.chen.handlerexception.MyHandlerExceptionResolver"/>
-
-
测试
-
//自定义异常 //异常一定要往外抛,让springmvc的异常处理器发现 @RequestMapping("/null") public void nullException() throws MyException { throw new MyException("空指针异常"); }
-
注解版的异常处理(利用@ControllerAdvice来为每一个请求处理方法增加逻辑处理)(这个于自定义异常处理器一样)
-
定义异常处理的处理方法
-
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中提供了两种方式)
- 实现HandlerInterceptor:需要实现所有的方法(但是在default关键词出现后,实现需要实现的方法)
- 实现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技术
- 对每一个请求都过滤
文件上传与下载
文件上传
-
依赖
-
<!-- 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的包-->
-
-
注入springmvc提供的文件解析器CommonsMultipartResolver
-
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> <!--beanFactory会寻找id为multipartResolver的bean所以id必须为这个id-->
-
-
测试
-
//单文件上传 @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;
}
浙公网安备 33010602011771号