话说
各位读者,晚上好!上一篇博客内容有点少,这一篇也是,主要是知识点琐碎,不怎么好玩。虽然不好玩,关键时候还是有用滴。这会就让我们总结下springMVC世界滴局部异常、全局异常和静态资源。
目录
一、整体布局
二、异常处理
三、静态资源处理
四、总结
开发工具IDEA(2017.2.5)
一、整体布局
二、异常处理
我们通过登录验证这个功能来演示如何自定义异常,然后再捕获这个异常,在登录未通过情况下显示异常信息。
1)常规方式提示
2)局部异常
3)全局异常
1)常规方式提示
假设用户名是admin且密码是123,跳转到主页面,如果不是,跳转回登录页面,并提示“用户名或密码不正确”。这时传参用HttpSession即可。因为需要在另外一个页面显示参数,所以,需要session.而Model和Request的作用域仅限一次请求。
package com.hmc.springmvc.controller;
import com.hmc.springmvc.exception.LoginException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* User:Meice
* 2017/11/12
*/
@Controller
public class LoginController {
/**
* 这个方法演示:
* 1、传参在重定向后用HttpSession
* 2、Model和Request一样,只是在单个请求中传参,只适合转发
*/
@RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("msg","权限不足,请重新登录!");
// req.setAttribute("msg","用户名或密码不正确,请重新登录!");
httpSession.setAttribute("msg","权限不足,请重新登录!");//这里用model 或者request存是没用的,因为他们都只是在
//单个请求中有效.
return "redirect:login.jsp";
}
}
}
但是我们想自定义异常,通过异常方式来捕获异常,并做提示:
捕获异常有两种方式:局部捕获和全局捕获
局部捕获:方法上加@ExceptionHandler(LoginException.class)
全部捕获:SimpleMappingExceptionResolver
局部捕获,存在的问题还是无法带参。
首先自定义异常类,如何自定义异常呢?
LoginException,继承运行过程中的异常,并重写方法
package com.hmc.springmvc.exception;
/**
* User:Meice
* 2017/11/12
*/
/**
* 自定义异常
*/
public class LoginException extends RuntimeException {
public LoginException() {
super();
}
public LoginException(String message) {
super(message);
}
public LoginException(String message, Throwable cause) {
super(message, cause);
}
public LoginException(Throwable cause) {
super(cause);
}
protected LoginException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2)局部异常
package com.hmc.springmvc.controller;
import com.hmc.springmvc.exception.LoginException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* User:Meice
* 2017/11/12
*/
@Controller
public class LoginController {
/**
* 这个方法演示:
*
* 1、自定义异常,抛出异常
* 2、局部异常与捕获异常
*
*/
// @ExceptionHandler(LoginException.class)
@RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req,Exception ex,Model model){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("ex",ex);//这样存,照样没效果
// httpSession.setAttribute("ex",ex); //运行结果:java.lang.Exception 没法捕获异常信息,因为throw就结束了
return "redirect:/login.jsp";
// throw new LoginException("用户名或者密码不正确!");
}
}
局部异常处理有些棘手,原因是:无法在页面跳转的时候把参数带过去。页面跳转势必需要重定向,一旦重定向,参数就不好传递;一旦throw,后面代码就无法执行。所以,用全局异常喽。
这个时候,可以看到我们自定义异常起作用了。
3)全局异常
这个是完整版本的代码(含常规方法、局部异常)
1、首先代码如下:
package com.hmc.springmvc.controller;
import com.hmc.springmvc.exception.LoginException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* User:Meice
* 2017/11/12
*/
@Controller
public class LoginController {
/**
* 这个方法演示:
* 1、传参在重定向后用HttpSession
* 2、Model和Request一样,只是在单个请求中传参,只适合转发
*/
/*@RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("msg","权限不足,请重新登录!");
// req.setAttribute("msg","用户名或密码不正确,请重新登录!");
httpSession.setAttribute("msg","权限不足,请重新登录!");//这里用model 或者request存是没用的,因为他们都只是在
//单个请求中有效.
return "redirect:login.jsp";
}
}*/
/**
* 这个方法演示:
*
* 1、自定义异常,抛出异常
* 2、局部异常与捕获异常
*
*/
// @ExceptionHandler(LoginException.class)
@RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req,Exception ex,Model model){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("ex",ex);//这样存,照样没效果
// httpSession.setAttribute("ex",ex); //运行结果:java.lang.Exception 没法捕获异常信息,因为throw就结束了
return "redirect:/login.jsp";
// throw new LoginException("用户名或者密码不正确!");
}
}
@RequestMapping(value = "login.htm",method = RequestMethod.GET)
public String login(){
return "login";
}
/**
* 全局异常
*/
@RequestMapping(value = "login.htm",method = RequestMethod.POST)
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req,Exception ex,Model model){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("ex",ex);//这样存,照样没效果
// httpSession.setAttribute("ex",ex); //运行结果:java.lang.Exception 没法捕获异常信息,因为throw就结束了
throw new LoginException("用户名或者密码不正确!");
//这里必须这么传参,否则携带不了错误信息
}
}
}
2、其次配置springmvc-servlet.xml
<!--全局异常处理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--异常映射-->
<property name="exceptionMappings">
<props>
<!--key表示异常类,value表示捕获异常后跳转界面-->
<prop key="com.hmc.springmvc.exception.LoginException">login</prop>
<prop key="java.langNullPointerException">error/error</prop>
//这里可以定义多个错误页面
</props>
</property>
<!--页面中默认的异常对象名,默认为exception 这里可以修改为ex-->
<property name="exceptionAttribute" value="ex"/>
</bean>
直接用session来存储错误信息多么简单!为什么要这么麻烦?一是要掌控异常,我们自己创建异常并运用;二是了解全局异常配置好处在于可以统一指定不同异常跳转界面;通过局部异常返回界面则容易混乱.
页面这么接收参数就可以了。
以下是默认异常名:exception
${exception}<br/>
${exception.message}
<hr/>
以下是修改异常名:ex
${ex}<br/>
${ex.message}
捕获后的异常:
三、静态资源处理
就是类似图片、CSS、JS这类文件的加载路径问题。
如果SpringMVC是以下这么配置的,就不用再操心静态资源管理,因为只要引用路径正确:项目名+文件夹+文件名,就可以找到:
<!--配置spring MVC核心-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
But!如果想用REST风格的话,如下配置,就会导致静态资源无法引用:
<!--配置spring MVC核心-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
那么如何搞定这个问题咧?
springmvc-servlet.xml中配置一下就行:
xmlns:mvc="http://www.springframework.org/schema/mvc"
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
<!--处理 服务器资源-->
<mvc:annotation-driven/>
<!--静态资源处理-->
<mvc:resources mapping="/resources/**" location="/resources/"/>
mapping就是要找的资源,这里表示resources下面所有的包所有的文件,location表示路径。
有什么用呢?这样的话,我们的静态资源(图片、CSS、JS)放到哪里都可以找到,即便放到WEB-INF下面也是可以找到的。总而言之,言而总之,就是让静态资源放的位置随心而欲!无论怎么“躲猫猫”,俺都可以找到你!
来来,补充完整版本的springmvc-servlet.xml
<?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.hmc.springmvc"/>
<!--处理 服务器资源-->
<mvc:annotation-driven/>
<!--静态资源处理-->
<mvc:resources mapping="/resources/**" location="/resources/"/>
<!--配置视图解析-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/Book/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--全局异常处理-->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!--异常映射-->
<property name="exceptionMappings">
<props>
<!--key表示异常类,value表示捕获异常后跳转界面-->
<prop key="com.hmc.springmvc.exception.LoginException">login</prop>
<prop key="java.langNullPointerException">error/error</prop>
</props>
</property>
<!--页面中默认的异常对象名,默认为exception 这里可以修改为ex-->
<property name="exceptionAttribute" value="ex"/>
</bean>
</beans>
完整版的web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<!--配置spring MVC核心-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
完整版的LoginController
package com.hmc.springmvc.controller;
import com.hmc.springmvc.exception.LoginException;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* User:Meice
* 2017/11/12
*/
@Controller
public class LoginController {
/**
* 这个方法演示:
* 1、传参在重定向后用HttpSession
* 2、Model和Request一样,只是在单个请求中传参,只适合转发
*/
/*@RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("msg","权限不足,请重新登录!");
// req.setAttribute("msg","用户名或密码不正确,请重新登录!");
httpSession.setAttribute("msg","权限不足,请重新登录!");//这里用model 或者request存是没用的,因为他们都只是在
//单个请求中有效.
return "redirect:login.jsp";
}
}*/
/**
* 这个方法演示:
*
* 1、自定义异常,抛出异常
* 2、局部异常与捕获异常
*
*/
// @ExceptionHandler(LoginException.class)
/* @RequestMapping("login.htm")
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req,Exception ex,Model model){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("ex",ex);//这样存,照样没效果
// httpSession.setAttribute("ex",ex); //运行结果:java.lang.Exception 没法捕获异常信息,因为throw就结束了
return "redirect:/login.jsp";
// throw new LoginException("用户名或者密码不正确!");
}
}*/
@RequestMapping(value = "login.htm",method = RequestMethod.GET)
public String login(){
return "login";
}
/**
* 全局异常
*/
@RequestMapping(value = "login.htm",method = RequestMethod.POST)
public String login(String username, String pwd, HttpSession httpSession, HttpServletRequest req,Exception ex,Model model){
if("admin".equals(username) && "123".equals(pwd)){
//model.addAttribute("username",username);//因为model传参作用域类似request,只在一次请求中有效
httpSession.setAttribute("username",username);
return "redirect:book/list.htm";
} else{
// model.addAttribute("ex",ex);//这样存,照样没效果
// httpSession.setAttribute("ex",ex); //运行结果:java.lang.Exception 没法捕获异常信息,因为throw就结束了
throw new LoginException("用户名或者密码不正确!");
}
}
}
完整版的login.jsp
<%--
User: Meice
Date: 2017/11/12
Time: 17:22
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
<title>用户登陆</title>
</head>
<body>
<%--这样访问的时候,配置里面如果是*.htm这样都是可以访问资源的,因为都会被spring mvc拦截 静态资源可以访问--%>
<%--<img src="/springmvc04/resources/images/abc.jpg">--%>
<%--如果要使用REST风格,不管什么情况,都给spring mvc处理--%>
<img src="/springmvc04/resources/images/abc.jpg">
<form action="login.htm" method="post">
<table>
<tr>
<td>用户名</td>
<td>
<input type="text" name="username"/>
</td>
</tr>
<tr>
<td>密码</td>
<td>
<input type="password" name="pwd"/>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登录">
</td>
</tr>
</table>
</form>
<hr/>
以下是默认异常名:exception
${exception}<br/>
${exception.message}
<hr/>
以下是修改异常名:ex
${ex}<br/>
${ex.message}
</body>
</html>
四、总结
1、以前登录权限验证时,把信息存储到session中,携带过去,现在我们通过异常来处理。首先自定义异常(一个类,继承RuntimeException并重写方法),重写方法里面就可以携带异常信息;
2、搞定异常有2种方式:局部和全局。局部在需要抛出异常方法上加注解:@ExceptionHandler(自定义异常的类.class);全局异常需要在springmvc-servlet.xml中配置,SimpleMappingExceptionResolver这个类的一些属性值,这里面配置需要捕获哪个类的异常及跳转页面。这么做的好处是避免局部异常跳转页面各不相同,造成混乱;
3、静态资源处理主要针对REST风格配置,为保证静态资源可以如丝滑般加载,配置mvc:就可以啦,感觉有点麻烦。
好了,晚安!下期再会!