• 整体框架还是选用Spring+SpringMVC+MyBatis
  • 连接池选用阿里巴巴的Druid
  • 项目管理使用的是Maven
  • 日志管理log4j
  • 安全框架使用Shiro
  • 页面模板引擎常用的FreeMarker
    (这个以前没用过,研究了不少时间)
  • 前台JavaScript+JQ+各类插件
  • 数据库MySql
    -

SSM框架的组装以前写过一个,这一篇就只是贴上大致的配置文件

1.配置文件

我们设为三类:
web.xml
框架xml
properties配置文件

1.web.xml

<?xml version="1.0" encoding="UTF-8"?>    
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
    xmlns="http://java.sun.com/xml/ns/javaee"    
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"    
    version="3.0">    
    <display-name>CMS About</display-name>    

    <welcome-file-list>    
        <welcome-file>/index.jsp</welcome-file>    
    </welcome-file-list>    

    <!-- 加载spring bean -->    
    <context-param>    
         <param-name>contextConfigLocation</param-name>    
        <param-value>classpath:applicationContext.xml</param-value>    
    </context-param>    
    <listener>    
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>    
    </listener>    

    <!-- 编码过滤器 -->    
    <filter>    
        <filter-name>encodingFilter</filter-name>    
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>    
        <async-supported>true</async-supported>    
        <init-param>    
            <param-name>encoding</param-name>    
            <param-value>UTF-8</param-value>    
        </init-param>    
    </filter>    
    <filter-mapping>    
        <filter-name>encodingFilter</filter-name>    
        <url-pattern>/*</url-pattern>    
    </filter-mapping>    
    <!-- shiro 安全过滤器-->
    <filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <async-supported>true</async-supported>
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>shiroFilter</filter-name>
        <url-pattern>/cms/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <!-- druid连接池 -->  
     <filter>
        <filter-name>DruidWebStatFilter</filter-name>
        <filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
        <init-param>
            <param-name>exclusions</param-name>
            <param-value>*. js ,*. gif ,*. jpg ,*. png ,*. css ,*. ico ,/ druid /*</param-value>
        </init-param>
     </filter>
     <filter-mapping>
        <filter-name>DruidWebStatFilter</filter-name>
        <url-pattern>/*</url-pattern>
     </filter-mapping>

     <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.WebStatFilter</servlet-class>
     </servlet>
     <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
     </servlet-mapping>
    <!-- Spring MVC servlet -->    
    <servlet>    
        <servlet-name>SpringMVC</servlet-name>    
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    
        <init-param>    
            <param-name>contextConfigLocation</param-name>    
            <param-value>classpath:spring-mvc.xml</param-value>    
        </init-param>    
        <load-on-startup>1</load-on-startup>    
        <async-supported>true</async-supported>    
    </servlet>    
    <servlet-mapping>    
        <servlet-name>SpringMVC</servlet-name>    
        <url-pattern>/cms/*</url-pattern>    
    </servlet-mapping>    

</web-app>    

2.ApplicationContext

这个是主要的引导文件,用于引入其他的配置文件

<?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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    

    <!-- 使用注解式注入 -->    
    <context:annotation-config />    

    <!-- 自动扫描 -->    
    <context:component-scan base-package="com.cms" />    

    <!-- 导入DAO配置 -->    
    <import resource="spring-dao.xml"/>    

    <!-- 导入数据库配置 -->    
    <import resource="spring-db.xml"/>    

    <!-- 导入数据库配置 -->    
    <import resource="spring-tx.xml"/>  

    <!-- shiro-->
    <import resource="classpath:spring-shiro.xml"/>   

</beans>   

3.spring-dao

dao接口配置文件,用于指定扫描的Dao所在的类以及SqlSessionFactory

<?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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    


    <!-- DAO接口所在包名,Spring会自动查找其下的类 -->    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">    
        <!--basePackage指定要扫描的包,在此包之下的映射器都会被搜索到。    
         可指定多个包,包与包之间用逗号或分号分隔-->    
        <property name="basePackage" value="com.cms.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>    
    </bean>                           

</beans>   

4.spring-db.xml

配置连接池的参数,注意,这里是引入jdbc.properties的信息。

<?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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    

    <!-- 引入配置文件 -->    
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">    
        <property name="location" value="classpath:jdbc.properties" />    
    </bean>    

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">    
        <property name="driverClassName" value="${driver}" />    
        <property name="url" value="${url}" />    
        <property name="username" value="${username}" />    
        <property name="password" value="${password}" />    
        <!-- 初始化连接大小 -->    
        <property name="initialSize" value="${initialSize}"></property>    
        <!-- 连接池最大数量 -->    
        <property name="maxActive" value="${maxActive}"></property>    
        <!-- 连接池最大空闲 -->    
        <property name="maxIdle" value="${maxIdle}"></property>    
        <!-- 连接池最小空闲 -->    
        <property name="minIdle" value="${minIdle}"></property>    
        <!-- 获取连接最大等待时间 -->    
        <property name="maxWait" value="${maxWait}"></property>    
    </bean>    

    <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    
        <property name="dataSource" ref="dataSource" />    
        <!-- 自动扫描mapping.xml文件 -->    
        <property name="mapperLocations" value="classpath:com/cms/dao/mapper/*.xml"></property>    
    </bean>    

</beans>  
  • jdbc.properties
driver=com.mysql.jdbc.Driver
url=jdbc\:mysql\://127.0.0.1\:3306/cms
username=root
password=123456
#\u5B9A\u4E49\u521D\u59CB\u8FDE\u63A5\u6570    
initialSize=0
#\u5B9A\u4E49\u6700\u5927\u8FDE\u63A5\u6570    
maxActive=20
#\u5B9A\u4E49\u6700\u5927\u7A7A\u95F2    
maxIdle=20
#\u5B9A\u4E49\u6700\u5C0F\u7A7A\u95F2    
minIdle=1
#\u5B9A\u4E49\u6700\u957F\u7B49\u5F85\u65F6\u95F4    
maxWait=60000

5.spring-tx.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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    

    <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->    
    <bean id="transactionManager"    
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    
        <property name="dataSource" ref="dataSource" />    
    </bean>    

</beans>  

6.spring-shiro.xml

这个是shiro最简单的一种

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <description>Shiro安全配置</description>
    <!-- 扫描service注入realm -->
    <context:component-scan base-package="com.cms.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>


    <!--securityManager是shiro的核心,初始化时协调各个模块运行-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
       <!--单个realm使用realm,如果有多个realm,使用realms属性代替
       <property name="realms">
        <list>
            <ref bean="AdminRealm"></ref>
            <ref bean="UserRealm"></ref>
        </list>
       </property>--> 
           <property name="realm" ref="UserRealm" />
       <property name="cacheManager" ref="shiroEhcacheManager" />
    </bean>


    <!--realm配置,realm是shiro的桥梁,它主要是用来判断subject是否可以登录及权限等
    <bean id="AdminRealm" class="com.cms.shiro.AdminRealm" />-->
    <bean id="UserRealm" class="com.cms.shiro.UserRealm" />

    <!-- <property name="userService" ref="userService"/></bean> 不扫描可采用此方法注入-->

            <!-- MD5校验
        <bean id="realm" class="com.qx.realm.MyRealm">    
            <property name="credentialsMatcher">    
                <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">    
                    <property name="hashAlgorithmName" value="MD5"></property>    
                    <property name="hashIterations" value="1024"></property>    
                </bean>    
            </property>    
        </bean>   -->    


    <!--shiro过滤器配置,bean的id值须与web中的filter-name的值相同-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
     <!-- 没有权限或者失败后跳转的页面 -->
     <property name="loginUrl" value="/index.jsp" /> 
     <property name="successUrl" value="/WEB-INF/static/cms/index.jsp" />
     <property name="unauthorizedUrl" value="/login/unauthorized" />
        <property name="filterChainDefinitions">
            <value>
                /cms/login=anon
                /cms/register=anon
                /cms/logining=anon
                /cms/main/**=authc
            </value>
        </property>
    </bean>
    <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
    <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>
    <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
  • shiro-ehcache.properties
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <diskStore path="java.io.tmpdir"/>
    <defaultCache maxElementsInMemory="10000" eternal="false" 
    timeToIdleSeconds="900" timeToLiveSeconds="1800" 
    overflowToDisk="false" 
    memoryStoreEvictionPolicy="LFU" />
    <cache name="testEhcache" 
        maxElementsInMemory="10000" 
        eternal="false"
        overflowToDisk="false" 
        timeToIdleSeconds="900"
        timeToLiveSeconds="1800"
        memoryStoreEvictionPolicy="LFU" />

</ehcache>

7.spring-mvc配置文件

MVC配置文件,包括添加扫描注解,视图设置,文件上传设置。

<?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:p="http://www.springframework.org/schema/p"    
    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-3.1.xsd      
                        http://www.springframework.org/schema/context      
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd      
                        http://www.springframework.org/schema/mvc      
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">    

    <!--避免IE执行AJAX时,返回JSON出现下载文件 -->    
    <bean id="mappingJacksonHttpMessageConverter"    
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">    
        <property name="supportedMediaTypes">    
            <list>    
                <value>text/html;charset=UTF-8</value>    
            </list>    
        </property>    
    </bean>    

     <!-- 添加注解驱动 -->      
    <mvc:annotation-driven />    
    <mvc:default-servlet-handler/>    

    <!-- 设置使用注解的类所在的包 -->    
    <context:component-scan base-package="com.cms.controller" />    

    <!-- 完成请求和注解POJO的映射 -->    
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">    
        <property name="messageConverters">    
            <list>    
                <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->    
            </list>    
        </property>    
    </bean>    

    <!-- 定义跳转的文件的前后缀 ,视图模式配置-->    
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">    
        <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->    
        <property name="prefix" value="/WEB-INF/static/cms/" />    
        <property name="suffix" value=".jsp" />    
    </bean>    

    <!-- SpringMVC上传文件时,需要配置MultipartResolver处理器-->    
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">      
        <!-- 默认编码 -->    
        <property name="defaultEncoding" value="utf-8" />      
        <!-- 文件大小最大值 -->    
        <property name="maxUploadSize" value="10485760000" />      
        <!-- 内存中的最大值 -->    
        <property name="maxInMemorySize" value="40960" />      
    </bean>     

</beans>    

2.Java代码

先贴出来,后面再一个个的来分析

1.首先,从登陆前台来看:

1.form表单提交,地址/CMS/cms/logining ,method是post

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%@ include file="/common/global.jsp" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http//www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
    <title>CMS</title>
<link rel="stylesheet" type="text/css" href="${ctxPath}/css/login.css">
</head>
<body style="background:#000;">
  <div class="png login_logo"><img src="${ctxPath}/images/login.jpg" alt=""></div>
  <div class="login">
  <form action="/CMS/cms/logining" method="post" class="loginAction" id="loginAction">
    <div class="login_1"><input id="name" name="name" type="name" /></div>
    <div class="login_2"><input id="password" name="password" type="password" /></div>
    <div class="login_3"><input name="" type="checkbox" value="" /></div>
    <div class="register"><a href="${ctxPath}/cms/register" style="color: wheat;text-decoration: none;">我要注册</a></div>
    <div class="login_4 png"><a href="javascript:submit();"><img src="${ctxPath}/images/login_08.jpg" /></a></div>
  </form>

  </div>
</body>
</html>
<script>
function submit(){
        if (document.getElementById("name").value == "") {
            alert("请输入姓名!");
            document.getElementById("name").focus();
            return false;
        }
        else if (document.getElementById("password").value == "") {
            alert("请输入密码");
            document.getElementById("password").focus();
            return false;
        }
        document.getElementById("loginAction").submit();
}
</script>


2.被后台接收,Controller

1.因为地址为logging,所以映射到
@RequestMapping(“/logining”)
public ModelAndView logining()

方法

package com.cms.controller;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.cms.entity.User;
import com.cms.service.LoginService;
import com.cms.service.UserService;

/**
*@author:gang
*@version:
**/
@Controller
public class loginController {
    @RequestMapping("/login")
    public ModelAndView login(){
        ModelAndView mView = new ModelAndView();
        mView.setViewName("login");
        return mView;
    }


//  测试String直接接收前台数据
//  public void test(HttpServletRequest request,
//          HttpServletResponse response, String username, String password){
//      System.out.println(username);
//      System.out.println(password);
//      ModelAndView mView = new ModelAndView();
//      mView.setViewName("main");
//  }
    /*此处可能会有疑问,感觉shiro的realm完全没有用上,这个是因为我们将shiro交给spring容器控制了,看shiro的配置文件我们就可以发现adminRealm确实被使用了*/
    @Resource
    private UserService userService;
    @Resource
    private LoginService loginService;

    @RequestMapping("/logining")
    public ModelAndView logining(HttpServletRequest request,
            HttpServletResponse response, String name, String password) {
        ModelAndView mv = new ModelAndView();
        User user = userService.getUserByName(name);
        password = userService.getPasswordByUtil(user,password);
        UsernamePasswordToken token = new UsernamePasswordToken(name,
                password);
        // 记录该令牌
        token.setRememberMe(false);
        // subject权限对象 
        Subject subject = SecurityUtils.getSubject();
        System.out.println(subject.isAuthenticated());
        String exceptionClassName = (String) request
                .getAttribute("shiroLoginFailure");
        //判断是否已登录
        if (subject.isAuthenticated()){
            subject.logout();
        }
        try {
            // 提交申请,验证能不能通过,也回调reaml里的doGetAuthenticationInfo验证是否通过
            subject.login(token);
            System.out.println(exceptionClassName);
        } catch (UnknownAccountException ex) {// 用户名没有找到
            mv.addObject("msg", "用户未找到");
//          ex.printStackTrace();
        } catch (IncorrectCredentialsException ex) {// 用户名密码不匹配
            mv.addObject("msg", "密码不正确");
//          map.put("msg", "密码不正确");
//          ex.printStackTrace();
        } catch (AuthenticationException e) {// 其他的登录错误
            mv.addObject("msg", "其他错误");
//          e.printStackTrace();
        } catch (Exception e) {
            mv.addObject("msg", "登录异常");
//          e.printStackTrace();
        }

        // 验证是否成功登录的方法
        if (subject.isAuthenticated()) {
            mv.setViewName("main");
        }else{
//          mv.setViewName("redirect:/login.jsp");
            mv.setViewName("login"); //此处偷懒,一般是ajax请求,或重定向时将失败传回
            loginService.setSessionKey(request, user);
        }
//      return new ModelAndView("redirect:/login.jsp");
        return mv;
    }

    // 退出
    @RequestMapping("/logout")
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }
    @RequestMapping("/register")
    public ModelAndView register(){
        ModelAndView regView = new ModelAndView();
        regView.setViewName("register");
        return regView;
    }
}

3.走到UserRealm验证

核心:
UsernamePasswordToken usernamePasswordToke = (UsernamePasswordToken)token;
String account = usernamePasswordToke.getUsername();
String pwd = String.valueOf(usernamePasswordToke.getPassword());
User user = this.userService.getUserByName(account);
。。。。。。。
if( !user.getUserPassword().equals(pwd)){
throw new IncorrectCredentialsException();
}
此处的user.getUserPassword()获取的是数据库的密码,这个我们进行过HASH加密,所以需要对输入的密码进行相同的加密(配合salt)
调用UserService

package com.cms.shiro;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import com.cms.entity.User;
import com.cms.service.UserService;


/**
*@author:gang
*@version:
**/
public class UserRealm extends AuthorizingRealm{

    @Autowired
    private UserService userService;

    /** 
     * 授权
     * <p>Title: doGetAuthorizationInfo</p> 
     * <p>Description: </p> 
     * @param principals
     * @return 
     * @see org.apache.shiro.realm.AuthorizingRealm#doGetAuthorizationInfo(org.apache.shiro.subject.PrincipalCollection) 
    */

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();//未进行授权处理
        return authorizationInfo;
    }

    /** 
     * 认证
     * <p>Title: doGetAuthenticationInfo</p> 
     * <p>Description: </p> 
     * @param token
     * @return
     * @throws AuthenticationException 
     * @see org.apache.shiro.realm.AuthenticatingRealm#doGetAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken) 
    */

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToke = (UsernamePasswordToken)token; 
        String account = usernamePasswordToke.getUsername();
        String pwd = String.valueOf(usernamePasswordToke.getPassword());
        User user = this.userService.getUserByName(account);
        if( user == null ){
            throw new UnknownAccountException();
        }
        if( !user.getUserPassword().equals(pwd)){
            throw new IncorrectCredentialsException();
        }
//      if(Boolean.TRUE.equals( user.getLocked())){
//            throw new LockedAccountException(); //帐号锁定
//      }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                account,pwd,this.getName()); //此处未进行密码加密处理
        return authenticationInfo;
    }

        @Override
        public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
            super.clearCachedAuthorizationInfo(principals);
        }

        @Override
        public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
            super.clearCachedAuthenticationInfo(principals);
        }

        @Override
        public void clearCache(PrincipalCollection principals) {
            super.clearCache(principals);
        }

        public void clearAllCachedAuthorizationInfo() {
            getAuthorizationCache().clear();
        }

        public void clearAllCachedAuthenticationInfo() {
            getAuthenticationCache().clear();
        }

        public void clearAllCache() {
            clearAllCachedAuthenticationInfo();
            clearAllCachedAuthorizationInfo();
        }

}

4.UserRealm调用UserService

通过以下方法获取加密后的密码
public String getPasswordByUtil(User user,String password)

package com.cms.service;



import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cms.dao.UserDao;
import com.cms.entity.User;
import com.cms.util.PasswordUtil;

/**
*@author:gang
*@version:
**/
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private PasswordUtil passwordUtil;

    public User addUser(String name,String password,String email,String country){
        User user = new User();
        user.setUserPassword(password);
        user.setUserName(name);
        user.setCountry(country);
        user.setEmail(email);
        Date date = new Date();
        user.setDate(date);
        passwordUtil.encryptPassword(user);
        userDao.addUser(user);
        return user;
    }

    public User getUserByName(String name) {
        // TODO Auto-generated method stub
        User user = new User();
        user = userDao.getUserByName(name);
        return user;
    }

    public String getPasswordByUtil(User user,String password){
        String hashPassword = passwordUtil.returnPassword(user,password);
        return hashPassword;
    } 


}
  • 实体类user
  • 可以看到这里有一个salt,这个是加密时用到的
package com.cms.entity;

import java.util.Date;

/**
*@author:gang
*@version:
**/
public class User {
    private String salt;
    private String name;
    private String password;
    private int Uid;
    private Date createTime;
    private String email;
    private String country;
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public String getUserName() {
        return name;
    }

    public void setUserName(String userName) {
        this.name = userName;
    }

    public String getUserPassword() {
        return password;
    }

    public void setUserPassword(String userPassword) {
        this.password = userPassword;
    }

    public int getUid() {
        return Uid;
    }

    public void setUid(int uid) {
        Uid = uid;
    }

    public Date getDate() {
        return createTime;
    }

    public void setDate(Date date) {
        this.createTime = date;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String hex) {
        // TODO Auto-generated method stub
        this.salt = hex;
    }


}
  • PasswordUtil.java

  • 可以看到salt是在这里被设置的

  • user.setSalt(randomNumberGenerator.nextBytes().toHex());
package com.cms.util;


import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Component;

import com.cms.entity.User;

/**
*@author:gang
*@version:
**/
@Component
public class PasswordUtil {
    //简单MD5加密
    public static String  getPassword(String password){return DigestUtils.md2Hex(password);}

    //
    private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    private String algorithmName = "md5";
    private final int hashIterations = 2;

    public void encryptPassword(User user) {
        // User对象包含最基本的字段Username和Password
        user.setSalt(randomNumberGenerator.nextBytes().toHex());
         // 将用户的注册密码经过散列算法替换成一个不可逆的新密码保存进数据,散列过程使用了盐
        String newPassword = new SimpleHash(algorithmName, user.getUserPassword(),ByteSource.Util.bytes(user.getSalt()), hashIterations).toHex();
        user.setUserPassword(newPassword);
    }
    //
    public String returnPassword(User user,String password) {
         // 将用户的注册密码经过散列算法替换成一个不可逆的新密码保存进数据,散列过程使用了盐
        String newPassword = new SimpleHash(algorithmName, password,ByteSource.Util.bytes(user.getSalt()), hashIterations).toHex();
        return newPassword;
    }

}

最后完成在前面对比完成,用户登录
此时根据前面的设置跳转到登录界面、

    // 验证是否成功登录的方法
        if (subject.isAuthenticated()) {
            mv.setViewName("main");
        }else{
//          mv.setViewName("redirect:/login.jsp");
            mv.setViewName("login"); //此处偷懒,一般是ajax请求,或重定向时将失败传回
            loginService.setSessionKey(request, user);
        }
//      return new ModelAndView("redirect:/login.jsp");
        return mv;

3.总结

我们一开始参加项目,最多的工作就是增删改查,其实,项目里面最核心的就是对数据库的处理,从数据库中取得数据,进行操作。

以上内容基本上占非增删改查操作的百分之六十,而一个项目的主要组成就是为实现业务进行增删改查。。。。

后面,将会对以上的代码进行实际中的总结。
(主要是理解不够深入,只能浮在表面~

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐