JavaWeb框架-SpringMVC-3-异常与静态资源处理

话说

各位读者,晚上好!上一篇博客内容有点少,这一篇也是,主要是知识点琐碎,不怎么好玩。虽然不好玩,关键时候还是有用滴。这会就让我们总结下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:就可以啦,感觉有点麻烦。


好了,晚安!下期再会!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值