SSM+Shiro:

1.利用IDEA快速创建SpringMVC环境

2.整合Spirng

⑴Web.xml中添加相关配置:

使用IDEA直接创建SpringMVC项目的话,不用再执行这一步,因为IDEA已经将spring和springmvc都整合进来.对于配置文件,默认是applicationContext.xml,在WEB-INF下,如果修改,可如下:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

⑵在applicationContext.xml中添加相关的配置:

包扫描,数据源,数据事务管理,annotation-driven,创建相应的文件结构,bean包,

<context:component-scan base-package="com.dong.*">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
    <!-- 配置数据源 -->
    <bean id = "dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.Driver}"></property>
        <property name="jdbcUrl" value="${jdbc.uri}"></property>
        <property name="user" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
        <property name="maxPoolSize" value="500"></property>
    </bean>

    <!-- 事务管理 -->
    <bean id = "DataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--开启基于注解的事务-->
    <tx:annotation-driven transaction-manager="DataSourceTransactionManager"></tx:annotation-driven>

3.整合SpringMVC

⑴在dispatcher-servlet.xml中配置视图解析器(用于对返回的视图名添加前缀和后缀),包扫描(用于扫描映射类),mvc:annotation-driven,用于兼容,mvc:default-servlet-handler:用于直接访问静态资源

 <!-- Spring MVC 只负责网站的跳转逻辑 -->
    <!-- 只扫描controller 组件 -->
    <context:component-scan base-package="com.dong.*"  use-default-filters="false">
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <mvc:annotation-driven ></mvc:annotation-driven>
    <mvc:default-servlet-handler></mvc:default-servlet-handler>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

注意:这里的dispatcher-servlet.xml如果没有指定,则使用默认的serlvetname-servlet.xml,如想指定:

 <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:dispatcher.xml</param-value>
        </init-param>
    </servlet>

4.整合Mybatis

⑴导入Jar包

⑵在spring的配置文件applicationContext.xml中进行配置:sqlSessionFactory,扫描mapper的映射路径,

   <bean id="SqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"></property>
        <property name="configLocation" value="classpath:config.xml"></property>
        <property name="mapperLocations" value="classpath:com/dong/mapper/*.xml"></property>
    </bean>

    <mybait-spring:scan base-package="com.dong.dao"></mybait-spring:scan>
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dong.dao"></property>
    </bean>

注意,这里需要在类路径下创建mybatis的配置文件,config.xml,也可以不用配置,但是在开发中尽量配置,同时,需要指定mapper.xml的映射路径

5.整合Shiro

⑴导入jar包,(主要是后7个jar,前几个是因为在项目中开发报错,提示该添加的jar)

⑵在web.xml中添加过滤器

    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <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>

⑶在applicationContext.xml中添加shiro的相关配置:realm,credentialsMatcher(非必须),缓存lifecycleBeanPostProcessorsecurityManager,shiroFilter.

 <bean id="myRealm" class="com.dong.realm.myrealm">
        <property name="credentialsMatcher" ref="credentialsMatcher" />
    </bean>
    <bean id="credentialsMatcher"
          class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="MD5" />
        <property name="hashIterations" value="1024" />
    </bean>

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    </bean>
    <!-- 配置 Bean 后置处理器: 会自动的调用和 Spring 整合后各个组件的生命周期方法. -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <!-- 启用shrio授权注解拦截方式 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 装配 securityManager -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 配置登陆页面 -->
        <property name="loginUrl" value="index.jsp"/>
        <!-- 登陆成功后的一面 -->
        <property name="successUrl" value="/views/success.jsp"/>
        <property name="unauthorizedUrl" value="/views/unauthorized.jsp"/>
        <!-- 具体配置需要拦截哪些 URL, 以及访问对应的 URL 时使用 Shiro 的什么 Filter 进行拦截.  -->
        <property name="filterChainDefinitions">
            <value>
                /index.jsp=anon
                /views/success.jsp=anon
                /logout = logout
                /images/** =anon
                /js/** = anon
                /styles/** = anon
            </value>
        </property>
    </bean>

⑷创建自定义的realm,并实现相应的认证和授权方法

package com.dong.realm;

import com.dong.service.userService2;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class myrealm extends AuthorizingRealm {
    @Autowired
    userService2 userService2;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        return null;
    }
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        System.out.println("----------->doGetAuthenticationInfo" + authenticationToken);

        //1.把AuthenticationToken类型的参数转换为UsernamePasswordToken类型
        UsernamePasswordToken usernamePasswordToken =(UsernamePasswordToken) authenticationToken;
        //2.从UsernamePasswordToken 中获取username
        String username = usernamePasswordToken.getUsername();
        System.out.println(userService2.getpassword(username));
        //3.调用数据库,获取username对应的记录

        System.out.println("------------------>从数据库中获取username:" + username + "用户所对应的信息");
        String check = userService2.checkusername(username);
        System.out.println(check.toString());
        //4.若用户不存在,抛异常
        if( check.equals("null")){
            throw new UnknownAccountException("用户不存在");
        }
        //5.根据用户信息的情况,决定是否需要抛出其他AuthenticationToken异常
        if("monster".equals(username)){
            throw new LockedAccountException("用户被锁定");
        }
        //6.根据用户情况,构建AuthenticationInfo对象并返回.通常使用的实现类为:SimpleAuthenticationInfo
        //以下信息是从数据库中获取:
        //1.princial:认证的实体信息, 可以是username,也可以是数据库中对应的实体
        Object principal = username;
        //2.从数据表中获取的密码
        //没有使用salt
        // Object credentials = 123456;
        //使用salt

        //3.realmName:当前realm对象的name,调用父类的getName()方法即可.
        String realName = getName();
        // SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,credentials,realName);
        //4.盐值
        //加入salt后,需要使用的info
        ByteSource credentialssalt = ByteSource.Util.bytes(username);
        Object credentials = userService2.getpassword(username);
        String hashAlgorithmName = "MD5";
        int hashIterations = 1024;
        Object result = new SimpleHash(hashAlgorithmName,credentials,credentialssalt,hashIterations);
        System.out.println("加密后的密码:" + result.toString());
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal,result,credentialssalt,realName);
        System.out.println("welcom role:" + userService2.getrole(username));
        return info;
    }

}

注意:这里的userservice是service层的方法,在调用方法的时候可以注入,并进行验证。

6.实现相关业务(用户认证)

⑴创建index.jsp,实现账号和密码的输入

  <table>
    <form action="shiroLogin" method="post">
    <tr>
      <td><B>你好 : 朋友 </B>
      <td>账号: <input type="text" name="username"> </td>
      <td>密码:<input type="password" name="password"></td>
      <td> <input type="submit" value="登录"> </td>
    </form>
      <td> <a  style="text-decoration: none" href="toregistered">注册 </a> </td>
    </tr>
  </table>

⑵创建控制器,并配置hall.jsp(略,hall.jsp随便定义)

package com.dong.controller;

import com.dong.service.userService2;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class shiroController {
    
    @RequestMapping("/shiroLogin")
    public String login(@RequestParam("username") String username, @RequestParam("password") String password){
        Subject currentUser = SecurityUtils.getSubject();

        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            try {
                currentUser.login(token);
                System.out.println("登录成功");
                return "hall";
            } catch (AuthenticationException ae) {
                System.out.println("登录失败 :" + ae.getMessage());
            }
        }
        return "redirect:index.jsp";
    }

}

注意:这里暂时将登陆的验证信息显示在后台,

⑶在realm的实现类中进行相应的修改,注入userService,其中的用户检测,获取密码都是通过userservice实现对dao层的调用,来查询数据库,这块咱们的realm不变,因为前面已经导入usreService

⑷创建service层,提供调用接口

package com.dong.service;

import com.dong.dao.userdao2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class userService2 {

    @Autowired
    private userdao2 mapper;
    public String getpassword(String username){
        return mapper.getuserpassword(username);
    }

    public String checkusername(String username){
        return mapper.checkusername(username);
    }
}

⑸创建mapper对象,即首先创建方法的接口类

package com.dong.dao;

import org.springframework.stereotype.Component;

@Component
public interface userdao2 {
    public String getuserpassword(String username);
    public String checkusername(String username);

}

⑹创建mapper配置文件,mapper放置在applicationContext.xml中进行配置的mapper扫描路径下

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-Mapper.dtd">
<!-- 名称空间 ,可以随便写,但是如果使用接口,则需要指定为接口的全类名,-->
<mapper namespace="com.dong.dao.userdao2">

    <select id="getuserpassword" resultType="String">
        SELECT PASSWORD
        FROM USER
        WHERE Account = #{username}
    </select>

    <select id="checkusername" resultType="String">
        SELECT Account
        FROM USER
        WHERE Account =#{username}
    </select>

</mapper>

最后:注意数据库表的创建,注意在本例中,我们只用到用户名和密码,所以在测试中,可以随便创建一张user表,只要有用户名和密码即可.

在案例的实际效果展示:(这个是本人最近在做的一个项目的一部分)

声明:我们的数据表中有一个用户: username: admin  ,password: 123456

输入正确的密码后台结果为:(打印的这些信息都是在程序中的设置的输入输出,为了方便查看效果)

当输入错误的密码:

 

 

 

谢谢观看,如有问题,敬请指出,与君共勉