Shiro

Shiro

  1. shiro是什么
    1. 是要给权限框架(安全框架)
    2. 类似的框架Spring Security
  2. shiro中的核心组件
    1. subject:和Shiro交互的主体都是subject
    2. SecurityManager:shiro核心的组件
    3. realm:安全数据源
  3. shiro能干什么
    1. 认证
    2. 授权
    3. 密码加密
    4. 会话管理
    5. 缓存

1.环境搭建

1.1导入jar包

shiro-all-1.3.2

shiro-core-1.3.2

1.2新建配置文件shiro.ini

[users]
#用户名=密码,角色1,角色2
admin=123,admin
qfadmin=123,qfadmin

[roles]
#角色名称=权限
admin = *
qfadmin=user:add,user.update

1.3测试

private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);
public static void main(String[] args) {
    
    // 1.创建SecurityManagerFactory
    Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
    // 2.通过SecurityManagerFactory得到securityManager
    SecurityManager securityManager = factory.getInstance();
    // 3.把securityManager设置到securityUtils,方便后期的获取(全局)
    SecurityUtils.setSecurityManager(securityManager);
    // 4.创建Subject
    Subject currentUser = SecurityUtils.getSubject();
    // 5.给Subje创建一个sesion
    Session session = currentUser.getSession();
    // 6.给属性添加一个键值对
    session.setAttribute( "someKey","aValue" );
    String value = (String) session.getAttribute("someKey");
    if (value.equals("aValue")) {
   		log.info("Retrieved the correct value! [" + value + "]");
    }
    // 7.根据key获取value
	String value = (String) session.getAttribute( "someKey" );
    // 8.判断
    if (value.equals("aValue")) {
    	log.info("从session中获取的value [" + value + "]");
    }
    // 9.判断用户是否登录
    if (!currentUser.isAuthenticated()){ // //如果没有登录就进行登录操作
        //封装用户名或密码
        UsernamePasswordToken token = new UsernamePasswordToken("lonestarr","vespa");
        //token.setRememberMe ( true); //设置记住我
        try {
            //登录
            currentUser.login(token);
        } catch (UnknownAccountException uae){ //未知的账户异常:用户不存在
            log.info("There is no user with username of " +token.getPrincipal());
        } catch (IncorrectcredentialsException ice) { //用户名或密码错误
            log.info("Password for account " + token.getPrincipal() + " was incorrect!");
        } catch (LockedAccountException lae) { //账户被锁定
            log.info("The account for username " + token.getPrincipal() + " is locked. "
        +"Please contact your administrator to unlock it.");
        } catch (AuthenticationException ae) { //其他认证异常,
        }
    }
	// 10.获取登录的用户名
    log.info("欢迎["+ currentUser.getPrincipal() + "]登录成功。。");
    // 11.判断该用户是否有某个角色
    if (currentUser.hasRole("schwartz")) {
        log.info("该用户有【schwartz】角色");
    }else {
    	log.info("该用户没有【schwartz】角色");
    }
    // 12.判断用户是否有这个权限
    if (currentUser.isPermitted("lightsaber : weild")) {
        log.info("该用户有【lightsaber :weild】权限");
    } else {
    	log.info("该用户没有【lightsaber : weild】权限");
    }
    // 13.注销
    currentUser.logout();
    // 14.
    System.exit(0);
}

2.shiro和spring整合

Shiro和Spring整合

  1. 添加jar包的依赖
    • spring
    • shiro
  2. 配置文件
    1. web.xml
      • 初始化Spring容器的监听器
      • shiroFilter
        • /*
    2. springmvc.xml
      • 开启包扫描
      • 。。。。
    3. applicationContext.xml
      • securityManager
      • lifecycleBeanPostProcessor
      • shiroFilter
        • 登陆成功后跳转的路径
        • 没有登陆时跳转登陆页面路径
        • 没有权限时跳转的路径
        • 一些过滤器

2.1导入依赖

<properties>
	<shiro.version>1.3.2</shiro.version>
</properties>

<!--shiro的依赖-->
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-quartz</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-guice</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-hazelcast</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-cas</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-aspectj</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.3.2</version>
</dependency>
<dependency>
	<groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.4</version>
</dependency>

2.2在applicationContext.xml中配置

<!--    shiro的核心组件-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="sessionMode" value="native"/>
        <!--把Realm配置到securityManager-->
        <property name="realm" ref="userRealm"/>
        <!--加入会话管理器-->
        <property name="sessionManager" ref="sessionManager"/>
        <!--加入rememberMeManager管理-->
        <property name="rememberMeManager" ref="rememberMeManager"/>
        <!--加入cacheManager管理-->
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

<!--	shiro的Realm ,自定义UserRealm-->
	<bean id="userRealm" class="com.dtf.realm.UserRealm">
		<property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!--加密的算法-->
                <property name-"hashAlgorithmName" valuem"MD5"></property>
                <!--加密次数-->
                <property name="hashIterations" walue="1024"></property>
            </bean>
    	</property>
        <!--启用缓存,默认false: -->
		<property name="cachingEnabLed" value="true"/>
        <!--启用身份验证缓存,即缓存AuthenticationInfo信息,默认false -->
        <property name="authenticationcachingEnabled" value="true"/>
        <!--缓存AuthenticationInfo信息的缓存名称-->
        <property name="authenticationcacheName" value="authenticationcache"/>
        <!--启用授权缓存,即缓存AuthorizationInfo信息,默认false -->
        <property name="authorizationcachingEnabled" value="true"/>
        <!--缓存AuthorizationInfo信息的缓存名称-->
        <property name="authorizationcacheName" value="authorizationcache"/>
	</bean>

<!--    可以自动配置spring容器中shiro bean 的生命周期方法-->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.lifecycleBeanPostProcessor"/>

<!--    shiroFilter:很重要-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!--引入securityManager-->
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/>
        <property name="successUrl" ref="/ok.jsp"/>
        <property name="unauthorizedUrl" ref="/unauthorized.jsp"/>
        <!--过滤器	  
				authc:必须要认证通过后才可以调用,通过记住我登陆不算
				anon:匿名的过滤器
				logout:注销
				user:认证成功或者通过记住我登陆成功都可以访问
		-->
        <property name="filterChainDefinitions">
            <value>
                /logout = logout
                /favicon.ico = anon
                /logo.png = anon
                /shiro.css = anon
                /s/login = anon
                /*.jar = anon
                /add = roles[admin]
                /update = perms[user:update]
                /** = user
                /** = authc
            </value>
        </property>
    </bean>

2.2.1 URL匹配模式

?:匹配一个字符

*:匹配零个或多个字符串

**:匹配路径中的零个或多个路径

2.3创建realm并在xml中配置

public class UserRealm extends AuthorizingRealm{
    //重写AuthorizationInfo(授权)和AuthenticationInfo(身份认证)
    /**
     *授权
     */
    Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
    //TOD0 Auto-generated method stub
        System.out.println("UserRealm.dcGetAuthorizationInfo()");
        SimpleAuthorizationInfo saiz = new SimpleAuthorizationInfo();
        //获取当前用户名称
		0bject username = principals.getPrimaryPrincipal();
        if("admin".equals(username.toString())){
            System.out.println("给admin添加role角色");
            HashSet<String> roles = new HashSet<String>();
            roles.add("admin");
			saiz.addRoles(roles);//添加角色
        } else if("qfAdmin".equals(username.toString())){
            Set<String> permissions - new HashSet<String>();
            permissions.add("user:udpate");
            saiz.addStringPermissions(permissions);//添加权则
        }
		return saiz;
    }
    /**
     *身份验证
     */
    eoverride
    protected AuthenticationInfo docetAuthenticationInfo( AuthenticationToken token) throws AuthenticationExce{
        //1.根据用户名查询密码
        Object username = token.getPrincipal();//获取的是UsernamePasswordToken对象中的第一个参数
    	String password = "admin";
        
        if("qfadmin".equals(username)){
            password="qfadmin";
        }
        
        //2.封装用户的密码
        //第一个参数是:用户名
        //第二个参数是:从数据库中查询出的密码
        //第三个参数是:realm名字
        SimpleAuthenticationInfo asci = new SimpleAuthenticationInfo(username,password,getName());
//        ByteSource salt = ByteSource.Util.bytes(username);
//        SimpleAuthenticationInfo asci = new SimpleAuthenticationInfo(username,password,salt,getName());

        
        System.out.println("userRealm.doGetAuthenticationInfo()");
        //3.返回给shiro
    	return asci;
    }
}
示例:
<!--	shiro的Realm ,自定义UserRealm-->
	<bean id="userRealm" class="com.dtf.realm.UserRealm"></bean>

<!--    在shiro的核心组件中添加-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" value="userRealm"/>
    </bean>

2.4在web.xml中配置shiro过滤器

<!--    这个filter的名字要和spring容器中的shiroFilter的id要保持一致,xml中-->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--    拦截到所有的请求,交给spring容器中的shiroFilter处理-->
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

2.5测试

package com.dtf.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class Usercontroller {
	@RequestMapping(value = "/login")
	public string login(String username,String password,String rememberMe) {
        
        //1.先得到当前用户
        Subject currentUser = SecurityUtiles.getSubject();
        
        //1.判断是否登录
        if (!currentUser.isAuthenticated()){ // //如果没有登录就进行登录操作
            //封装用户名或密码
            UsernamePasswordToken token m new UsernamePasswordToken(username,password);
            
            try {
                if("1".equals(rememberMe)){
                    token.setRememberMe (true); //设置记住我
                }
                //登录
                currentUser.login(token);
            } catch (UnknownAccountException uae){ //未知的账户异常:用户不存在
                System.out.println("There is no user with username of " +token.getPrincipal());
            } catch (IncorrectcredentialsException ice) { //用户名或密码错误
                System.out.println("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) { //账户被锁定
                System.out.println("The account for username " + token.getPrincipal() + " is locked. "
            +"Please contact your administrator to unlock it.");
            } catch (AuthenticationException ae) { //其他认证异常,
                System.out.println("认证失败");
                return "login";
            }
        }
		return "ok";
	}
    @RequiresPermissions(value = "user:add")//必须有该权限才可以访问
    @RequestMapping(value = "/add")
    public String add(){
        System.out.println("UserController.add");
        return "ok";
    }
    @RequiresRoles(value = "admin")//必须有该角色才可以访问
    @RequestMapping(value = "/update")
    public String update(){
        System.out.println("UserController.update");
        return "ok";
    }
}

package com.dtf.relam;
public class MD5Utiles{
public static void main(String[] args){
        // 1.加密算法
        String algorithmName = "MD5";
   		// 2.名码
        0bject source = "admin";
    	// 3.盐值
        0bject salt = ByteSource.Util.bytes("admin");//盐值一般是用户名或者userId
    	// 4,加密次数
        int hashIterations = 1024;
        SimpleHash simpleHash = new SimpleHash(algorithmName,source,salt,hashIterations);
        // 5.得到加密后的密码
        System.out.println(simpleHash);
    }
}

3.身份认证(见2.5)

登录认证

  • realm
    • 认证
    • 授权
      • 权限
      • 角色
  • 很多的过滤器

4.密码加密(见2.5)

加密

  • 盐值加密解决加密后密码一致的问题

5.授权

控制权限

  • 过滤器:没有权限会直接跳转到没有权限页面
  • 注解和标签:没有权限会直接抛出异常

5.1 授权方式

1.编程式

1.注解式

	@RequiresRoles(value = "admin")//必须有该角色才可以访问    
    @RequestMapping(value = "/add")
    public String add(){
        System.out.println("UserController.add");
        return "ok";
    }
    @RequiresPermissions(value = "user:update")//必须有该权限才可以访问
    @RequestMapping(value = "/update")
    public String update(){
        System.out.println("UserController.update");
        return "ok";
    }

在springmvc.xml中添加:

    <aop:config proxy-target-class="true" />
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSource">
          <property name="securityManager" ref="securityManager" />
    </bean>


常用注解

1.@RequiresRoles

//:表示当前Subject需要角色admin和user
@RequiresRoles(value={"admin","user"}, logical= Logical.AND)

2.@RequiresPermissions

//:表示当前Subject需要权限user:a 或user:b
@RequiresPermissions (value={"user:a","user:b"}, logical=Logical.OR)

给登陆用户授权

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    //1.得到登录用户
    String username = (String)principals.getPrimaryPrincipal();
    Set<String> permissionSet = new HashSet<String>();
    if("admin".equals(username)){
        permissionSet.add("user:add");
        permissionSet.add( "user:query"); // admin用户具有user:add和user: query权限
    }else if("qf".equals(username)){
        permissionSet.add( "user:update" );
        permissionSet.add( "user:delete" ); // qf用户具有user:update和user:delete权限
    }
    //接收权限相关的信息
    SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
	simpleAuthorizationInfo.setstringPermissions(permissionSet); //收置权限	   
//    simpleAuthorizationInfo.setRoles(roles);//这里也可以设置角色
	return simpleAuthorizationInfo;
}


2.JSP/GSP 标签

在JSP/GSP页面通过相应的标签完成

<shiro:hasRole name="admin">
<!--有权限-->
</shiro:hasRole>


shiro标签

1.导入标签库

<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro”%>

2.guest标签
用户没有身份验证时显示相应信息,即游客访问信息:

<shiro:guest>
欢迎游客访问,<a href="${pageContext.request.contextPath}/login.jsp">登录</a>
</shiro:guest>

3.user标签
用户己经经过认证/记住我登录后显示相应的信息。

<shiro:user>
欢迎[<shiro:principal/>]登录,<a href="${pageContext.request.contextPath}/logout">退出</a></shiro:user>

4.authenticated标签
用户已经身份验证通过,即 Subject.login登录成功,不是记住我登录的。

<shiro:authenticated>
用户[<shiro:principal/>]已身份验证通过
</shiro:authenticated>

4.notAuthenticated标签
用户未进行身份验证,即没有调用Subject.login进行登录,包括记住我自动登录的也属于未进行身份验证。

<shiro:notAuthenticated>
	未身份验证(包括记住我)
</shiro:notAuthenticated>

5.principal标签
显示用户身份信息,默认调用Subject.getPrincipal()获取,即 Primary Principal。

<shiro: principal/>

6.hasRole标签
如果当前Subject有角色将显示body体内容。

<shiro:hasRole name="admin">
	用户[<shiro:principal/>]拥有角色 admin<br/>
</shiro:hasRole>

7.hasAnyRoles标签

<shiro:hasAnyRoles name="admin,user">
	用户[<shiro:principal/>]拥有角色 admin 或user<br/>
</shiro:hasAnyRoles>

8.lacksRole标签
如果当前Subject没有角色将显示 body体内容。

<shiro:lacksRole name="abc">
	用户[<shiro:principal/>]没有角色 abc<br/>
</shiro:lacksRole>

6.RememberMe

applicationContext.xml中配置:

<!-- 会话Cookie模板-->
<bean id="rememberNeCookie" class="org.apache.shiro.web.servlet.SimpleCoohie">
    <constructor-arg value="sid" />
    <!--设置js是否可以访问cookie,true不能访问-->
    <property name="httpOnly" value="true"/>
    <!--保存时长30天,以秒为单位-->
    <property name="maxAge" value="2592000" />
</bean>
<!-- rememberMe管理器-->
<bean id="rememberMeManager" class="org.apache, shiro.web.mgt.CookieRememberNeManage">
    <!-- ipherKey是加密remembenMe Cookie的密钥;默认AES算法-->
    <property name="cipherKey" value="#{T(org.apache,shiro.codec.Base64).decode('4AvVhmFLUsOKTA3Kprsdag==')}"/>
    <!--引入上面定义的cookie模板-->
	<property name="cookie" ref="rememberMeCookie" />
</bean>
<!--    shiro的核心组件-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="rememberMeManager" ref="rememberMeManager"/>
    </bean>
<!--    shiroFilter:很重要-->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<!--引入securityManager-->
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/>
        <property name="successUrl" ref="/ok.jsp"/>
        <property name="unauthorizedUrl" ref="/unauthorized.jsp"/>
        <!--过滤器	 
				user:认证成功或者通过记住我登陆成功都可以访问
		-->
        <property name="filterChainDefinitions">
            <value>
                /** = user
            </value>
        </property>
    </bean>

为什么要换成user拦截器呢,下面就要说说user和authc的区别了,在上面的比较中也有。

user

用户己经身份验证或者记住我登录的都可以访问。

authc

必须认证之后才可以访问,通过记住我登录不能进行访问。用authc来检查一些关键操作,比如支付,即使用户使用了记住我登录也要再次确认用户的身份,以确保当前用户还是你。

@Controller
public class Usercontroller {
	@RequestMapping(value = "/login")
	public string login(String username,String password,String rememberMe) {
        UsernamePasswordToken token m new UsernamePasswordToken(username,password);
        if("1".equals(rememberMe)){
              token.setRememberMe (true); //设置记住我
        }
    }
}

7.shiro缓存

shiro的缓存

  • 配置缓存管理器
  • 缓存管理器添加到核心组件中
  • 在realm中设置启动缓存
    • 开启shiro缓存
    • 开启省份认证的缓存
    • 设置是否认证使用的缓存策略
    • 开启授权的缓存
    • 设置授权缓存使用的策略
  • 在ehcache.xml中添加省份认证和授权的缓存策略

Shiro提供了类似于Spring 的Cache抽象,即 shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现。这里我们使用Ehcache。

7.1Realm缓存

为什么要使用Realm 缓存?
现在我们学习了认证和授权后会发现这么一个问题,用户每发一次请求shiro都会调用授权的方法。而真正的项目中用户的权限是动态的从数据库中查询的,这样的就导致用户每发一次请求都要查询该用户的权限,这样的肯定会存在性能问题。而一般我们查询用户的权限只需要查询一次就可以,这时候就可以利用缓存。第一次查询出来后放入到缓存里面,下次直接去缓存中获取,当用户更新权限后也要清空缓存。
shiro中提供了对认证信息和授权信息的缓存。shiro默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的。主要原因是授权信息缓存,因为授权的数据量大。
用户认证通过。
该用户第一次授权:调用realm查询数据库
该用户第二次授权:不调用realm查询数据库,直接从缓存中取出授权信息(权限标识符)。

1.导入EhCache的jar包和EhCache的配置文件

<dependency>
	<groupId>net.sf.ehcache</groupId>
    <artifactId>ehcache</artifactId>
    <version>2.10.4</version>
</dependency>

ehcache.xml从ehcache的jar包中解压到项目

<ehcache xmlns:xsim"http://www.w3.org/2801/XNLSchema-instance" xsi:noNamespaceSchemaL
	<diskStore path="java.io.tmpdir"/>
	<defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToldleSecondsm"120"
            timeToLiveSeconds="120"
            maxElementsonDisk="10088080"
            diskExpiryThreadIntervalSeconds="120"
            memorystoreEvictionPolicy="LRU">
        <persistence strategy="LocalTempSwap"/>
    </defaultcache>

	<cache name="authorizationCache"
		maxEntriesLocalHeap="2003"
        eternal="false"
		timeToIdleSeconds="3600"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        statistics="true">
 	</cache>

	<cache name="authenticationcache"
        maxEntriesLocalHeap="2000"
        eternal="false"
    	timeToIdleSecondsm"3600"
        timeToLiveSeconds="3"
        overflowToDisk="false"
        statistics="true">
    </cache>

</ehcache>

2.配置EhCache缓存

2.1在spring中开启缓存(applicationContext.xml)

<!--缓存管理器-->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
	<!-- cache配置文件-->
	<property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
</bean>

<!--    shiro的核心组件-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <!--加入cacheManager管理-->
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

<!--	shiro的Realm ,自定义UserRealm-->
	<bean id="userRealm" class="com.dtf.realm.UserRealm">
		<property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <!--加密的算法-->
                <property name-"hashAlgorithmName" valuem"MD5"></property>
                <!--加密次数-->
                <property name="hashIterations" walue="1024"></property>
            </bean>
    	</property>
        
        <!--启用缓存,默认false: -->
		<property name="cachingEnabled" value="true"/>
        <!--启用身份验证缓存,即缓存AuthenticationInfo信息,默认false -->
        <property name="authenticationcachingEnabled" value="true"/>
        <!--缓存AuthenticationInfo信息的缓存名称-->
        <property name="authenticationcacheName" value="authenticationcache"/>
        <!--启用授权缓存,即缓存AuthorizationInfo信息,默认false -->
        <property name="authorizationcachingEnabled" value="true"/>
        <!--缓存AuthorizationInfo信息的缓存名称-->
        <property name="authorizationcacheName" value="authorizationcache"/>
	</bean>

springmvc全局的异常处理

<!--全局的异常处理-->
<bean
class="org.springframework.web.servlet.handler.SimpLeMappingExceptionResolver">
    <!--默认的错误视图页面-->
    <property name="defaultErrorview" valuem"error" />
    <!--错误视图页面可以通过${ex}获取异常信息 -->
    <property name="exceptionAttribute" value="ex" />
    <property namem"exceptionMappings">
        <props>
            <!--
                异常处理和制.
                    系统出现异常后先看当前异常是否配置
                        a)如果配置了当前异常就跳转到对应的错误视图
                        b)如果没有配置
                    1)再看当前异常的父类是否配置
                        a)如果配置了就通知到对应的错误视图
                        b)如果父类异常异常也没有配置,就跳转到默认的错误视图
            -->
            <prop key="java.lang.RuntimeException">
                error1
            </prop>
        </props>
    </property>
</bean>

maven项目启动,添加tomcat插件

<build>    
	<plugins>
        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <configuraction>
                <contextReloadable>true</contextReloadable>
                <port>8080</port>
                <path>/</path>
            </configuraction>
        </plugin>
    </plugins>
</build>

原文地址:https://www.cnblogs.com/dutf/p/14091539.html