精华内容
下载资源
问答
  • SpringSecurity安全框架

    万次阅读 多人点赞 2019-01-24 10:07:38
    Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架;它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC, DI 和 AOP 功能,为应用系统...
    框架简介:

    Spring Security 是一个能够为基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案的安全框架;它提供了一组可以在 Spring 应用上下文中配置的 Bean,充分利用了 Spring IoC, DI 和 AOP 功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

    简单的说,就是我们可以控制用户登陆的权限,通过配置让不同权限的用户登录后所看到页面不同,所能操作的内容也不同,本篇博客介绍security简单的配置和使用。

    环境搭建

    目录结构:
    在这里插入图片描述
    1.POM文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>cn.itcast</groupId>
        <artifactId>spring-security-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
        <packaging>war</packaging>
    
    
        <properties>
            <spring.version>4.2.4.RELEASE</spring.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-web</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.security</groupId>
                <artifactId>spring-security-config</artifactId>
                <version>4.1.0.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>servlet-api</artifactId>
                <version>2.5</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <!-- java 编译插件 -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.2</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <configuration>
                        <!-- 指定端口 -->
                        <port>9090</port>
                        <!-- 请求路径 -->
                        <path>/</path>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    2.测试用的首页Index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
    <h3>Hello My Cookie !</h3>
    </body>
    </html>
    

    3. web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
             version="3.1">
    
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-security.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        <!--security过滤器-->
        <filter>
            <filter-name>springSecurityFilterChain</filter-name>
            <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>springSecurityFilterChain</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    
        <!-- 指定默认访问的首页 -->
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>
    </web-app>
    

    4.security配置文件spring-security.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/security
                http://www.springframework.org/schema/security/spring-security.xsd">
    
        <!-- 页面拦截规则 -->
        <!--
        use-expressions 为是否使用使用 Spring 表达式语言( SpEL ) ,
        默认为 true ,如果开启,则拦截的配置:
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        -->
        <http use-expressions="false">
            <!-- intercept-url 表示拦截页面 -->
            <!--/* 表示的是该目录下的资源,只包括本级目录不包括下级目录-->
            <!--/** 表示的是该目录以及该目录下所有级别子目录的资源-->
            <intercept-url pattern="/**" access="ROLE_USER"/>
            <!--form-login 为开启表单登陆-->
            <form-login/>
        </http>
    
        <!-- 认证管理器 -->
        <authentication-manager>
            <authentication-provider>
                <user-service>
                <!--/** 测试登录用的用户名和密码.ROLE_USER代表权限-->
                    <user name="admin" password="123456" authorities="ROLE_USER"/>
                </user-service>
            </authentication-provider>
        </authentication-manager>
    </beans:beans>
    
    测试环境:

    启动服务器,访问 localhost:9090 ,本来我们应该是能够直接进入指定的 index.html 首页,但是安全控制器拦截下了我们,并且跳转到了系统自动生成的login页面
    在这里插入图片描述
    我们在输入了自定义的账号和密码后才能够正常访问页面,这里Spring Security框架的作用就体现出来了, 他能够帮助我们控制用户的权限,让不同权限的用户访问同一页面的内容不同,从而增加应用的安全性。

    实际的开发中,我们会使用自己定义的界面作为跳转的界面,下面简单介绍下如何配置:
    自定义的登陆页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆</title>
    </head>
    <body>
    
    <form action='/login' method='POST'>
        <table>
            <tr>
                <td>用户名:</td>
                <td><input type='text' name='username' value=''></td>
            </tr>
            <tr>
                <td>密码:</td>
                <td><input type='password' name='password'/></td>
            </tr>
            <tr>
                <td colspan='2'><input name="submit" type="submit"
                                       value="登陆"/></td>
            </tr>
        </table>
    </form>
    
    </body>
    </html>
    

    登陆失败的页面:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登陆失败</title>
    </head>
    <body>
    
    <h3 style="color : red;">验证失败 !</h3>
    </body>
    </html>
    

    修改spring-security.xml配置文件:

    首先,要看配置我们自定义的页面不被拦截:

        <!-- 以下页面不被拦截 security="none" 页面不被拦截,即不登陆也能访问 -->
        <http pattern="/login.html" security="none"></http>
        <http pattern="/login_error.html" security="none"></http>
    

    设置表单登陆:

      <!--form-login 为开启表单登陆-->
            <!--
            login-page:指定登录页面。
            authentication-failure-url:指定了身份验证失败时跳转到的页面。
            default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面。
            -->
            <form-login  login-page="/login.html" authentication-failure-url="/login_error.html"
                         default-target-url="/index.html"/>
    

    关闭 csrf,如果不关登录后不管成功或者失败都会报错误:

    <csrf disabled="true"/>
    

    CSRF(Cross-site request forgery):跨站请求伪造,也被称为“One Click Attack”或者 SessionRiding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。

    当使用html页面时,不关闭就会报错:
    在这里插入图片描述
    整体spring-security.xml配置文件:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans:beans xmlns="http://www.springframework.org/schema/security"
                 xmlns:beans="http://www.springframework.org/schema/beans"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/security
                http://www.springframework.org/schema/security/spring-security.xsd">
    
        <!-- 以下页面不被拦截 -->
        <http pattern="/login.html" security="none"></http>
        <http pattern="/login_error.html" security="none"></http>
    
        <!-- 页面拦截规则 -->
        <!--
        use-expressions 为是否使用使用 Spring 表达式语言( SpEL ) ,
        默认为 true ,如果开启,则拦截的配置:
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        -->
        <http use-expressions="false">
            <!-- intercept-url 表示拦截页面 -->
            <!--/* 表示的是该目录下的资源,只包括本级目录不包括下级目录-->
            <!--/** 表示的是该目录以及该目录下所有级别子目录的资源-->
            <intercept-url pattern="/**" access="ROLE_USER"/>
    
    
            <!--form-login 为开启表单登陆-->
            <!--
            login-page:指定登录页面。
            authentication-failure-url:指定了身份验证失败时跳转到的页面。
            default-target-url:指定了成功进行身份验证和授权后默认呈现给用户的页面。
            -->
            <form-login  login-page="/login.html" authentication-failure-url="/login_error.html"
                         default-target-url="/index.html"/>
    
            <!--csrf disabled="true" 关闭 csrf ,如果不加会出现错误-->
            <csrf disabled="true"/>
        </http>
    
        <!-- 认证管理器 -->
        <authentication-manager>
            <authentication-provider>
                <user-service>
                    <user name="admin" password="123456" authorities="ROLE_USER"/>
                </user-service>
            </authentication-provider>
        </authentication-manager>
    
    </beans:beans>
    

    谢谢 !

    展开全文
  • shiro安全框架

    万次阅读 2012-11-28 10:28:03
    Shiro 是 JAVA 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性...在 2009 年 3 月初之前,这个安全框架叫做 J-security,由于某些原因,更名为 Shiro(或

    Shiro 是 JAVA 世界中新近出现的权限框架,较之 JAAS 和 Spring Security,Shiro 在保持强大功能的同时,还在简单性和灵活性方面拥有巨大优势。本文就带领读者一睹 Shiro 的风采。

    可能大家早先会见过 J-security,这个是 Shiro 的前身。在 2009 年 3 月初之前,这个安全框架叫做 J-security,由于某些原因,更名为 Shiro(或者 Ki,意为 Fortress),是 Apache 的孵化项目,鉴于本文编写时 Shiro 的还没有正式发布的版本,本文使用的是 Jsecurity 的稳定版本 0.9,本文中 Shiro 等同于 Jsecurity。

    本文将涉及 Shiro 的整体框架、安全模型、关键概念类,同时给出了 Shiro 以及 Grails Shiro Plugin 的使用示例,可以下载文中使用的源代码。

    本文代码的开发环境:

    • Jsecurity 0.9
    • Grails 1.2.0
    • Grails Shiro Plugin 1.0.1
    • SpringSource Tool Suite 2.3

    Shiro 是一个强大而灵活的开源安全框架,能够非常清晰的处理认证、授权、管理会话以及密码加密。如下是它所具有的特点:

    1. 易于理解的 Java Security API;
    2. 简单的身份认证(登录),支持多种数据源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
    3. 对角色的简单的签权(访问控制),支持细粒度的签权;
    4. 支持一级缓存,以提升应用程序的性能;
    5. 内置的基于 POJO 企业会话管理,适用于 Web 以及非 Web 的环境;
    6. 异构客户端会话访问;
    7. 非常简单的加密 API;
    8. 不跟任何的框架或者容器捆绑,可以独立运行。

    目前还有其他出现较早的安全框架,比如 JAAS,Spring Security。

    JAAS —面世的时间最早,但是鉴于其在使用上有很大的限制,很少有人真正的使用它。可以说它不是一个好的应用程序级别的安全框架;

    Spring Security —目前是 Java 安全框架领域当之无愧的老大,已经非常成熟了;如果使用 Spring 框架,可以首选 Spring Security,但是对于单应用来说,Shiro 更显简单方便。

    下面就开始我们的 Shiro 之旅吧!

    首先,我们来看看的 Shiro 的整体架构,见下图:


    图 1. 整体架构
    图 1. 整体架构

    从上图可以看出,Shiro 主要有四个组件:

    1. SecurityManager

      典型的 Facade,Shiro 通过它对外提供安全管理的各种服务。

    2. Authenticator

      对“Who are you ?”进行核实。通常涉及用户名和密码。

      这个组件负责收集 principals 和 credentials,并将它们提交给应用系统。如果提交的 credentials 跟应用系统中提供的 credentials 吻合,就能够继续访问,否则需要重新提交 principals 和 credentials,或者直接终止访问。

    3. Authorizer

      身份份验证通过后,由这个组件对登录人员进行访问控制的筛查,比如“who can do what”, 或者“who can do which actions”。Shiro 采用“基于 Realm”的方法,即用户(又称 Subject)、用户组、角色和 permission 的聚合体。

    4. Session Manager

      这个组件保证了异构客户端的访问,配置简单。它是基于 POJO/J2SE 的,不跟任何的客户端或者协议绑定。

    Shiro 的认证和签权可以通过 JDBC、LDAP 或者 Active Directory 来访问数据库、目录服务器或者 Active Directory 中的人员以及认证 / 签权信息。SessionManager 通过会话 DAO 可以将会话保存在 cache 中,或者固化到数据库或文件系统中。

    从 Shiro 的框架图,已经能够体会到这个工具的简单了。下面让我们来看看 Shiro 是如何工作的。先了解一下它的安全模型吧!见下图:


    图 2. 安全模型
    图 2. 安全模型

    上图中,涉及了 Shiro 的五个概念:

    • Subject 是安全领域术语,除了代表人,它还可以是应用。在单应用中,可将其视为 User 的同义词。
    • Principal 是 Subject 的标识,一般情况下是唯一标识,比如用户名。
    • Role 和 Permission 分别代表了不同粒度的权限,从上图中可以看出 Role 的粒度更大些,Permission 代表了系统的原子权限,比如数据的修改、删除权限。对于简单的权限应用,可以不需要 Permission。
    • Realm 是一个执行者,负责真正的认证和鉴权。

    实现应用的安全模块的关键在于:定义合适的 role 和 permission,这就需要遵循如下原则:

    1. role 没有实质内容,只是代表一组 permission,目的是为了管理的方便,一般都是动态定义;
    2. permission 一般都是预先定义好的,不允许动态改变,除非源代码改动,它才会变化,它是整个安全模块的基础;
    3. 要使 permission 也能动态定义,并非不可能,但是这将使鉴权非常复杂,甚至可能导致鉴权语句遍布整个程序,得不偿失;
    4. 当然有一个例外:如果知道 permission 动态定义的规则和鉴权规则,如 Grails 的 fileter 中“${controllerName}:${actionName}:${params.id}”也可实现 permission 的动态定义

    理解 Shiro 的架构和安全模型了,我们来看看更具体些的内容。下图显示了 Shiro 中的关键概念类(参考资料 -- JSecurity Mini Guide)。


    图 3. 关键类
    图 3. 关键类

    AuthenticationToken 和 AuthenticationInfo

    前者在认证前使用,描述认证所需的信息,最常用的就是 username 和 password 对;后者在认证后使用,内容同前,但是表示已经经过认证的信息。

    RememberMe

    代表的是一种可能状态,并不表示该 Subject 已经经过了认证。对于一些普通的操作,这种可能状态并无大碍,但一旦涉及安全敏感的操作,必须经过认证。

    Credentials 和 CredentialsMatcher

    Credentials 是 Subject 的证书,在认证时使用,最常用的就是 password。在通常情况下,为了安全起见,Subject 的 credentials 都需要加密保存,于是 CredentialsMatcher 的作用就体现出来了,见下图:


    图 4. CredentialsMatcher 的作用
    图 4. CredentialsMatcher 的作用

    这里 CredentialsMatcher 需要将加密后的证书跟用户登录时提供的证书进行比对,完成认证的过程。

    PAM= Pluggable Authentication Modules

    在有多个 Realm 的时候使用。由认证策略决定认证结果,即 PAM= Relams + 认证策略。一般的策略有 3 种:AllSuccessful、AtLeastOneSuccessful 和 FirstSuccessful。

    AuthorizationInfo

    可以看成是 Role + Permission 的组合体。

    PermissionResolver 和 Permission

    它们之间的关系如下:


    图 5. PermissionResolver 和 Permission 的关系
    图 5. PermissionResolver 和 Permission 的关系

    在 Shiro 中,权限被转化为一种字符串描述(字符串分级表示,称之为 WildcardPermission),从而将权限转化为类似于对象 equals 的操作(Shiro 中的 implies 方法)。

    内置的权限有 2 个:

    • AllPermission,总是返回 true
    • WildcardPermission,权限字符串的表示方式。

    这里重点声明一下。WildcardPermission 是 Shiro 的精妙之处,我们可以将权限表示成字符串,这样对权限的控制可以不拘泥于物理存储,比如对 messagge 类具有修改和删除权限可以标识为:message:update,delete:*,其中‘ * ’表示所有;第一级分隔符为‘ : ’;第二级分隔符为‘ , ’,而对于权限字符串的解释完全可以由应用自己来定。

    如果要比较权限字符串,可以使用 permission1.implies(permission2),它分别比较对应位置的字符串,在如下情况中,结果会返回 true:

    • permission1 中的子串有 * 或 permission1 子串 ==permission2 子串;
    • permission1 无子串,permission2 有;
    • permission1 有子串,permission2 无,permission1 的所有子串都是 *。

    总的说来,Shiro 中的 Permission 需要注意如下内容:

    1. 权限的比较实际是字符串的比较,只不过是考虑到了字符串的分级
    2. 字符串的分级划分完全由使用者自己决定,Shiro 的惯例是 3 级:资源 : 操作 : 实例。
    3. 字符串的使用必须一致,分隔符之间不要有空格,避免无意间引入的不一致。如:定义使用“file : create, update : 1”,而验证使用“file : update”,那么分解之后一个是“ update ”,一个是“ update”,因空格而引起不等。

    Realm

    这是一个实际访问安全实体的组件,一般是应用相关的,跟数据源的关系是 1-1。它负责完成认证和鉴权,getAuthenticationInfo 代表了 login 的尝试,鉴权方法则由 Authorizer 继承而来。此处也体现了 Shiro 代码的另一个特点,通过继承来扩充功能。以常用的 JdbcRealm 为例,其继承链如下:


    图 6. JdbcRealm 的继承链
    图 6. JdbcRealm 的继承链

    Session

    它关联一个 Subject 的上下文,其作用类似于在 HttpSession 中保存用户标识,session 一旦过期,则重新登录。Shiro 的 Session 是独立的,其目的是做到环境无关性。为了利用 Web 环境中,Shiro 实现了一个直接使用 HttpSession 的 WebSession。

    SecurityManager

    这是一个 Façade 接口,=Authenticator + Authorizer + SessionFactory。在整体框架图中已经看到了它在 Shiro 中所处的位置。其特点同 Realm,一样是使用继承不断地扩充功能。对于 Web 应用一般使用 DefaultWebSecurityManager。

    Filter

    在 Web 环境下使用 filter 进行认证和权限检查是毋庸置疑的,而 Shiro 的特点则在于由一个主 Filter 将一群子 filter 串起来:


    图 7. Filter 的作用
    图 7. Filter 的作用

    在实际使用时,须注意:

    1. web.xml 中只需配置 JSecurityFilter。对于 Spring 应用,则使用 SpringJSecurityFilter;
    2. 子 filter 作为主 filter 的配置参数值出现,特点是:顺序相关
      1.  
        • 对于多个 URL,验证顺序是由上至下,类似 Exception 的匹配。因此,使用顺序应该是由细到粗。
        • 对于同一 URL,子 filter 的验证顺序是从左至右的 AND 操作。
    3. 如果配置值中含有分隔符,如 Permission,就需要使用引号来转义。

    Subject

    subject 代表了一个用户的状态和操作,它提供了所有安全相关的操作,包括认证和签权。可以将其视为另一种形式的 Façade。缺省实现是将这些操作委派给其内部包含的 SecurityManager。

    Configuration

    configuration 负责将所有这些组件串起来,最终创建 SecurityManager。在 Shiro 中,缺省格式是 ini。整个配置关系如下图:


    图 8. 配置关系
    图 8. 配置关系

    其中:

    • JSecurityFilter 创建 Configuration 实例,并将 ini 参数值传给 Configuation。在 Spring 环境中,分别使用 SpringJSecurityFilter 和 SpringIniWebConfiguration。
    • Configuration 实际就是 SecurityManager 的 Factroy,对 SpringIniWebConfiguration 而言,它需要知道 SecurityManager 的 BeanName,该值由 SpringJSecurityFilter 的初始化参数“securityManagerBeanName”值决定。即 SpringJSecurityFilter,实际有两个初始化参数:
    •  
      • config,是 ini 配置文件内容
      • securityManagerBeanName,是 SecurityManager 的 BeanName

    SecurityUtils

    这是 Shiro 中最重要的工具类,由它可以方便地获得 Subject 和 SecurityManager。

    杂项

    • AOP,提供 AOP 方面的支持,实现对某个类某个方法的拦截,从而使权限控制延伸至类的方法。
    • Cache,提供缓存支持
    • Codec,提供编码方面的支持
    • Crypto,提供加密支持
    • IO,从多个资源位置读写原始数据
    • JNDI,提供 jndi 支持
    • util,工具类支持
    • 标签类,用于 Web 页面

    对 Shiro 有了一个感官认识后,下面我们就亲自动手试试这个框架吧!下面给大家举了两个使用案例。

    在开始案例的学习之前,先作好准备工作 -- 获得 Shiro 相关的 jar 包,获取途径有两种:

    1. 直接到 J-security 的网站上 下 载,本文用到的就是这个;
    2. 由于 Shiro 目前是 Apache 的孵化项目,还没有发布正式的版本,但是我们可以到 Subversion 上下载代码,之后使用 Maven 构建

      mkdir shiro

      cd shiro

      svn co https://svn.apache.org/repos/asf/incubator/shiro/trunk/

      mvn install

    之后会得到 shiro-all-1.0-incubating-SNAPSHOT.jar,就可以使用 Shiro 了。

    示例一:让 Shiro 为你的应用服务

    这个案例中,我们使用 Grails 向大家讲述 Shiro 的使用。我们要实现如下功能:

    1. 用户登录后方可进入系统;
    2. 假定一个 message 的安全内容,用户可以创建 message 的内容,但是如果需要修改 / 删除 message 的内容就必须具有相应的权限;
    3. Admin 具有所有的权限;
    4. message 的权限跟角色关联。

    示例程序执行的流程如下:


    图 9 程序执行的流程
    图 9 程序执行的流程

    从上图中可以看到,任何人要访问应用中受保护的 URL,首先要通过 Filter 检查用户是否经过认证;对于没有认证的用户会将访问定向到登录页面;对于已经认证的用户,会对用户进行鉴权,这个用户是否具有访问其所提交的 URL 的权限;而管理员可以给角色授权。

    好了,开始程序的编写啦!

    创建安全领域类

    最常见的就是 User、Role 和 Permission,见清单 1。


    清单 1. User/Role/Permission 的 Domain class

    				
    class User {
    String username
    String password
    static hasMany= [roles: Role]
    static belongsTo= Role
    ……
    }
    class Role {
    String rolename
    static hasMany= [users: User, permissions: Permission]
    ……
    }
    class Permission {
    String permission

    static hasMany= [roles: Role]
    static belongsTo= Role
    ……
    }

     

    这里使用了最简单的情形,即权限传递结构为:Permission -> Role -> User。通常情况下,Permission 也可以分配给单个 User。

    创建一个安全实体

    实体名为 message,见清单 2。只有经过授权的用户才能对这个实体进行修改和删除。


    清单 2. message 的 Domain class

    				
    class Message {
    String details
    User user
    static constraints = {
    }
    }

     

    配置 web.xml


    清单 3. 在 web.xml 加入 SecurityFilter 的内容:

    				
    <filter>
    <filter-name>SecurityFilter</filter-name>
    <filter-class>
    org.jsecurity.spring.SpringJSecurityFilter
    </filter-class>
    <init-param>
    <param-name>securityManagerBeanName</param-name>
    <param-value>jsecSecurityManager</param-value>
    </init-param>
    </filter>
    <filter-mapping>
    <filter-name>SecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

     

    这里需要注意:

    • 这个 Filter 应该在 Grails 的 web.xml 中所有缺省的 Filter 最后;
    • url-pattern 不要使用“/**”,因为这样会造成登录页的 css 和图片无法访问。解决办法,可以通过遵循“只能通过 Controller/Action 访问”这个规则,并使用 Grails 的 Filter 机制,可以保证所有安全 URL 不被非法访问。

    创建 realm


    清单 4. conf/spring/resources.groovy

    				
    beans = {
    credentialMatcher(
    org.jsecurity.authc.credential.Sha1CredentialsMatcher) {
    storedCredentialsHexEncoded = true
    }

    permissionResolver(
    org.jsecurity.authz.permission.WildcardPermissionResolver)

    realm(org.jsecurity.realm.jdbc.JdbcRealm){
    permissionResolver = ref("permissionResolver")
    dataSource = ref("dataSource")
    permissionsLookupEnabled= true
    permissionsQuery= "select permission from
    permission, role_permissions, role where
    permission.id= permission_id and role_id= role.id and rolename= ?"
    userRolesQuery= "select rolename from role, role_users, user
    where role.id=role_id and user_id= user.id and username=?"
    authenticationQuery= "select password from user where username=?"
    }

    jsecSecurityManager(
    org.jsecurity.web.DefaultWebSecurityManager) {
    bean ->bean.destroyMethod = "destroy"
    realms = [ ref("realm") ]
    }
    }

     

    这里使用了 JdbcRealm,同时根据应用情况修改了相应的 SQL。如果允许 Permission 直

    接分配给 User,即 Permission 和 User 之间是多对多关系,那么 permissionsQuery 应该使用 union,即“role 相关 permission union user 相关 permission”。对于 User 有多个 Role 的情况,JdbcRealm 会循环得出总的结果。

    安全守护神:SecurityFilters

    下面就是我们的安全守护神:SecurityFilters,这里遵循 Grails 的 Filter 语法。见清单 5。


    清单 5. SecurityFilters

    				
    import org.jsecurity.SecurityUtils

    class SecurityFilters {
    def filters = {
    authc(controller:'*', action:'*', ) {
    before = {
    if(controllerName!='auth'){
    def subject = SecurityUtils.subject
    if (!subject.authenticated) {
    redirect(
    controller: 'auth',
    action: 'login',
    params: [
    targetUri: request.forwardURI - request.contextPath
    ])
    return false
    }
    }
    }
    }

    admin(controller: 'user|role|permission', action: '*'){
    before = {
    def subject= SecurityUtils.subject
    if(!subject.hasRole('admin')){
    redirect(controller: 'auth', action: 'unauthorized')
    return false
    }
    }
    }

    editmessage(controller: 'message', action: 'update|delete'){
    before = {
    def subject= SecurityUtils.subject
    if(!subject.isPermitted(
    "${controllerName}:${actionName}:${params.id}")){
    redirect(controller: 'auth', action: 'unauthorized')
    return false
    }
    }
    }
    }
    }

     

    代码中 :

    • authc 表示的是所有用户对应用系统的任何访问都要经过 auth 认证,对于没有认证的用户的访问会重定向到登录界面;
    • admin 表示的是属于 admin 角色的用户对 user/role/permission 具有所有权限,对于非 admin 角色的用户会对其提示没有 user/role/permission 的访问权限;
    • editmessage 表示当用户对 message 进行修改或者删除的时候对其进行鉴权,只有具有 message 的 update/delete 权限的用户才能对 message 进行修改。

    在上述代码中还可以看出,我们通常可以由 SecurityUtils 为出发点获得 Subject 和 SecurityManager。需要注意的是,认证的 Filter(authc)要打头阵。

    认证的代码


    清单 6. 认证代码

    				
    def signIn = {
    // 创建 AuthenticationToken
    def authToken = new UsernamePasswordToken(
    params.username,
    params.password)
    if (params.rememberMe) {
    authToken.rememberMe = true
    }
    try{
    // 使用 SecurityManager 的 login 登录
    this.jsecSecurityManager.login(authToken)
    flash.message = message(code: "$params.username")
    def targetUri = params.targetUri ?: "/"
    log.info "Redirecting to '${targetUri}'."
    redirect(uri: targetUri)
    }
    catch (AuthenticationException ex){
    // 如果出现异常,显示出错信息
    log.info "Authentication failure for user '${params.username}'."
    flash.message = message(code: "login.failed")
    def m = [ username: params.username ]
    if (params.rememberMe) {
    m['rememberMe'] = true
    }
    if (params.targetUri) {
    m['targetUri'] = params.targetUri
    }
    redirect(action: 'login', params: m)
    }
    }

     

    授权部分很简单,即对安全实体进行 CRUD。其中 Permission 的权限字符串根据实际情况形成,在本例中:

    •  
      •  
        • 如果对所有 message 具有修改权限,权限字符串可以为:message:delete,update:*;
        • 如果针对某一个 message 具有修改权限,权限字符串可以为:message:update,delete:messageid。

    示例二:使用 Shiro Plugin 快速构建安全模块

    在示例一中,所有的代码都是自己手动写的,这就对初学者要求有些高了。但可喜的是 Grails 社区有了 Shiro 的 plugin,让我们的工作变得非常简单。同样示例一的功能,看看 plugin 能够给我们带来什么样的惊喜?

    使用步骤如下:

    1. 安装 Shiro Plugin,在你的 grails 项目中运行:grails install-plugin shiro, 会创建 grails-app/realms 目录,并提供如下新的 Grails 命令:
      • grails create-auth-controller,创建 AuthController 以及登录窗口,Controller 提供了登录、登出和权限验证失败处理等 Action。
      • grails create-db-realm,创建一个访问数据库的 Realm
      • grails create-ldap-realm,创建一个访问 ldap 的 Realm
      • grails create-wildcard-realm,创建一个访问数据库的 Realm,但使用的是 Shiro 的 WildcardPermission。
      • grails quick-start,它是 create-auth-controller 和 create-db-realm 的集合体,是 Shiro 的快速入门,在接下来的内容中将详细介绍它的使用。
    2. 下面进行 Shiro 快速入门。在 grails 项目的目录下执行:grails quick-start,这个命令会创 建如下内容:
      • 在 grails-app/realms 下创建 ShiroDbRealm,这个 realm 是访问控制的信息库,用来决定一个用户有权访问哪些内容;
      • 在 grails-app/domain 创建 ShiroRole.groovy 和 ShiroUser.groovy;
      • 在 grails-app/controllers 下创建 AuthController,这里提供了登录和退出的 action;
      • 在 grails-app/views 下创建 auth 文件夹以及 login.gsp;
      • 在 grails-app/conf/ 下创建 SecurityFilters.groovy,这里管理着对所有 controller 和 action 的访问控制。
    3. 启动程序,当访问 controller 的时候,页面就会重定向到登录页面。但是这个时候是无法登录,因为我们没有添加用户。
    4. 进入到 grails-app/conf/ 修改 BootStrap.groovy, 

      清单 7. 修改后的 BootStrap.groovy
      				
      def init = { servletContext ->
      def user = new User(username: "user",
      passwordHash: new Sha1Hash("user").toHex())
      user.save()
      def role= new Role(name:"admin").addToUsers(user).save()
      }

      重新启动程序,就能使用 user/user 登陆了。

    5. 在 plugin 缺省创建的 SecurityFilters 中使用了对所有 URL 进行 before 拦截,但是我们根据实际情况进行修改,例如我们要示例一的 filter 内容,就可以做如下更改: 

      清单 8. 更改后的 SecurityFilters
      				
      auth(controller: "*", action: "*"){
      before={
      accessControl{true}
      }
      }
          management(controller: "user|role|permission", action: "*"){
      before={
      accessControl{role("admin")}
      }
      }
      message(controller: "message", action: "delete|update"){
      before={
      accessControl{   
              permission("message:${actionName}:${params.id}")
      }
      }
      }

      看到这里,读者可能已经注意到了,这里的代码比示例一中的 Filter 的代码简单的许多。对,Shiro 插件已经将示例一中的类似代码封装到 ShiroGrailsPlugin.groovy 中了,我们使用的时候只需要:

      调用 accessControl 方法,该方法的参数可以是 Map、Closure 或者 Map+Closure;

      使用 role( …… ),验证访问对象是否具有相应的角色;

      使用 permission( …… ),验证访问对象是否具有相应的 Permission。

    6. 授权部分内容参见上一示例,这里不做冗述。
    7. Shiro Plugin 中除了为我们提供了上述方便之外,还提供了一些常用的 taglib 来增强用户界面 , 这些 taglib 都在 pluginPath/grails-app/taglib /ShiroTagLib.groovy 中定义,我们可以直接在 gsp 中使用它们。

      比如,只有具有修改权限的用户才能够看到一些修改类的按钮显示,可以这样写:



      清单 9. Taglib 的使用
      				
      <shiro:hasPermission permission="message:update,delete">
      <span class="button">
      <g:actionSubmit class="edit" value="Edit" />
      </span>
      <span class="button">
      <g:actionSubmit class="delete"
      οnclick="return confirm('Are you sure?');"
      value="Delete" />
      </span>
      </shiro:hasPermission>

      如下是经常使用到的 Tag:

      • principal, 输出当前用户的标识
      • hasRole,判断当前用户是否属于给定的角色,参数:name
      • hasPermission, 判断当前用户是否具有指定的权限,参数:type,action 或者 permission
      • isLoggedIn, 判断当前用户是否已经登录
      • hasAnyRole,判断当前用户是否属于给定的某个角色,参数:in

    更多的 Tag 请参考 Shiro Plugin 的 gapi 的文档。

    如果您已经非常了解了 Shiro,可以采用示例一的方式自己写所有的代码,但是对于初学者,作者还建议使用 Shiro plugin,这个插件帮助我们生成了安全相关的基本内容,以及提供了方便的 Tag。

    读到这里,是不是觉得 Shiro 真的不错?!

    这里给大家举的示例只是抛砖引玉。Shiro 真正的精髓还需要在项目中慢慢的体会。本文是引领我们走向 Shiro 的第一步。在这里要感谢胡键对本文编写的大力支持。

    源代码中,shiroApp 是示例一的源代码,ShiroPlugin 是示例二的源代码。

    下载本文中的示例代码


    展开全文
  • Spring Security安全框架入门篇

    万次阅读 2016-02-04 00:02:05
    、Spring Security介绍:Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架(简单说是对访问权限进行控制嘛)。它提供了一组可以在Spring应用上下文中配置的Bean,...

    一、Spring Security相关概念

    1.1.、Spring Security介绍:

    Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架(简单说是对访问权限进行控制嘛)。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

    1.2、Spring Security实现原理:

    Spring Security对Web安全性的支持大量地依赖于Servlet过滤器。通过这些过滤器拦截进入请求,判断是否已经登录认证且具访问对应请求的权限。

    要完成访问控制,Spring Security至少需要下面四个拦截器(调度器、认证管理器、权限资源关联器、访问决策器)进行配合完成:

    <!-- mySecurityInterceptor这里我们把它命名为调度器吧 -->
    <!-- 必须包含 authenticationManager,securityMetadataSource,accessDecisionManager 三个属性 -->   
    <!-- 我们的所有控制将在这三个类中实现 --> 
    <!-- 它继承AbstractSecurityInterceptor类并实现了Filter接口 --> 
    <bean id="mySecurityInterceptor" class="com.luo.Filter.MySecurityInterceptor">  
        <b:property name="authenticationManager" ref="authenticationManager" />  
        <b:property name="securityMetadataSource" ref="securityMetadataSource" />  
        <b:property name="accessDecisionManager" ref="accessDecisionManager" />  
    
    </bean>  
    
    <!-- 认证管理器,实现用户认证的入口 -->  
    <authentication-manager alias="authenticationManager">  
        <authentication-provider user-service-ref="myUserDetailService" />   
    </authentication-manager>  
    
    <!-- 在这个类中,你就可以从数据库中读入用户的密码,角色信息等 -->  
    <!-- 主要实现UserDetailsService接口即可,然后返回用户数据 -->  
    <bean id="myUserDetailService" class="com.luo.Filter.MyUserDetailService" />  
    
    <!-- 权限资源关联器,将所有的资源和权限对应关系建立起来,即定义某一资源可以被哪些角色访问 -->  
    <!-- 它实现了FilterInvocationSecurityMetadataSource接口 -->  
    <bean id="securityMetadataSource" class="com.luo.Filter.MyFilterInvocationSecurityMetadataSource" /> 
    
    <!--访问决策器,决定某个用户具有的角色,是否有足够的权限去访问某个资源 --> 
    <!-- 它实现了AccessDecisionManager接口 --> 
    <bean id="accessDecisionManager" class="com.luo.Filter.MyAccessDecisionManager">

    看完上面的配置,可能未必能够完全明白,下面我们再进一步说明。

    (1)首先我们自定义一个过滤器(调度器,这里我们命名为mySecurityInterceptor),这个过滤器继承AbstractSecurityInterceptor类(这里先说明,本文但凡不是自定义的类或接口都是Spring Security提供的,无须深究)。 它至少包含 authenticationManager,accessDecisionManager,securityMetadataSource三个属性,我们的所有控制将在这三个类中实现。

    (2)登录验证:自定义类MyUserDetailService实现UserDetailsService接口和其loadUserByUsername方法,这个方法根据用户输入的用户名,从数据库里面获取该用户的所有权限细信息(统称用户信息)。Spring Security的AuthenticationProcessingFilter拦截器调用authenticationManager,类MyUserDetailService拿到用户信息后,authenticationManager对比用户的密码(即验证用户),如果通过了,那么相当于通过了AuthenticationProcessingFilter拦截器,也就是登录验证通过。

    (3)资源访问控制:MySecurityInterceptor继承AbstractSecurityInterceptor、实现Filter是必须的。登陆后,每次访问资源都会被MySecurityInterceptor这个拦截器拦截,它首先会调用MyFilterInvocationSecurityMetadataSource类的getAttributes方法获取被拦截url所需的权限,在调用MyAccessDecisionManager类decide方法判断用户是否够权限。

    可能文字描述还是比较抽象,通过实例应该能让大家更加清楚其原理。


    补充说明一下:

    UserDetailsService在身份认证中的作用:

    Spring Security中进行身份验证的是AuthenticationManager接口,ProviderManager是它的一个默认实现,但它并不用来处理身份认证,而是委托给配置好的AuthenticationProvider,每个AuthenticationProvider会轮流检查身份认证。检查后或者返回Authentication对象或者抛出异常。

    验证身份就是加载响应的UserDetails,看看是否和用户输入的账号、密码、权限等信息匹配。此步骤由实现AuthenticationProvider的DaoAuthenticationProvider(它利用UserDetailsService验证用户名、密码和授权)处理。

    因此,登录认证其实可以不实现UserDetailsService,而是实现AuthenticationProvider,然后在AuthenticationProvider里面获取用户输入的用户名和密码进行校验也是可以的。或者两者一起使用。

    下面推荐两者一起使用的方式http://blog.sina.com.cn/s/blog_4adc4b090102uy2f.html

    另外,只实现AuthenticationProvider而不实现UserDetailsService的方式,这类是重写AuthenticationProvider的authenticate方法的代码:

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String inputLoginId = authentication.getName();   //获取用户输入的用户名
        String inputPasswd = authentication.getCredentials().toString(); /获取用户输入的密码
    
        LOGGER.info("用户{}登录", inputLoginId);
        try{
            // 查询此用户信息
            myUser myUser = null;  //根据用户名到数据库里面查询用户数据
            if (myUser == null ) {
                throw new Exception("您输入的账号不存在");
            }
            if (myUser.getUserStatus() == UserStatus.locked) {
                throw new Exception("您的账号已被锁定");
            }
    
            String encodedPassword = myUser.getLoginPasswd();
            // 校验密码是否正确
            boolean authenticated = verifyPassword(inputPasswd, encodedPassword);
            if (authenticated) {
                // 认证成功处理
                updateLoginInfo(myUser.getLoginId(), 0, null);
            } else {
                // 认证失败处理
                authenticateErrorProcess(portalUser);
            }
    
            List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
            for (MyRole myRole : myUser.allRoleList()) {
                grantedAuths.add(new SimpleGrantedAuthority(myRole.getRoleCode()));
            }
            MyAuthUser authUser = new PortalAuthUser(inputLoginId, inputPasswd, true, true, true, true, grantedAuths);
            authUser.setPortalUser(portalUser);
            return new UsernamePasswordAuthenticationToken(authUser, null, authUser.getAuthorities());
        }catch(Exception e){
            LOGGER.warn("用户登录失败", e);
            throw new Exception(" 请确认用户名或者密码是否正确);
        }
    }

    二、Spring Security实例详细说明

    本实例环境:eclipse + maven
    本实例采用的主要技术:spring + springmvc + spring security

    时间有限这里只对其访问控制原理进行了阐述,例子后面再补上,不过关于实例推荐参考博文:http://blog.csdn.net/u012367513/article/details/38866465,这篇文章写得非常详细!!!

    这是春节前最后一篇博客了,过年回来还有另外的学习计划,可能这个例子的TODO有点遥遥无期啊……..哈哈

    展开全文
  • SSM框架原理,作用及使用方法

    万次阅读 多人点赞 2017-09-06 09:17:06
    作用: SSM框架是spring MVC ,spring和mybatis框架的整合,是标准的MVC模式,将整个系统划分为表现层,controller层,service层,DAO层四层 使用spring MVC负责请求的转发和视图管理 spring实现业务对象管理,...

    作用

    SSM框架是spring MVC ,spring和mybatis框架的整合,是标准的MVC模式,将整个系统划分为表现层,controller层,service层,DAO层四层

    使用spring MVC负责请求的转发和视图管理

    spring实现业务对象管理,mybatis作为数据对象的持久化引擎


    原理

    SpringMVC:

    1.客户端发送请求到DispacherServlet(分发器)

    2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller

    3.Controller调用业务逻辑处理后,返回ModelAndView

    4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图

    5.视图负责将结果显示到客户端


    Spring:我们平时开发接触最多的估计就是IOC容器,它可以装载bean(也就是我们Java中的类,当然也包括service dao里面的),有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。


    Mybatis:mybatis是对jdbc的封装,它让数据库底层操作变的透明。mybatis的操作都是围绕一个sqlSessionFactory实例展开的。mybatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。



    使用方法

    要完成一个功能:

    1. 先写实体类entity,定义对象的属性,(可以参照数据库中表的字段来设置,数据库的设计应该在所有编码开始之前)。
    2. 写Mapper.xml(Mybatis),其中定义你的功能,对应要对数据库进行的那些操作,比如 insert、selectAll、selectByKey、delete、update等。
    3. 写Mapper.java,将Mapper.xml中的操作按照id映射成Java函数。
    4. 写Service.java,为控制层提供服务,接受控制层的参数,完成相应的功能,并返回给控制层。
    5. 写Controller.java,连接页面请求和服务层,获取页面请求的参数,通过自动装配,映射不同的URL到相应的处理函数,并获取参数,对参数进行处理,之后传给服务层。
    6. 写JSP页面调用,请求哪些参数,需要获取什么数据。

    DataBase ===> Entity ===> Mapper.xml ===> Mapper.Java ===> Service.java ===> Controller.java ===> Jsp.  


    ====================================================================================================================================

    Spring MVC  拥有控制器,作用跟Struts类似,接收外部请求,解析参数传给服务层
    Spring 容器属于协调上下文,管理对象间的依赖,提供事务机制
    mybatis 属于orm持久层框架,将业务实体 与数据表联合 起来


    Spring MVC  控制层,想当与 Struts的作用
    Spring 控制反转和依赖注入  创建对象交由容器管理,达到了解耦的作用
    mybatis 主要用来操作数据库(数据库的增删改查)


    IOC:控制反转,是一种降低对象之间耦合关系的设计思想,面试的时候最好能说出来个例子,加深理解。例子:租房子,以前租房子需要一个房子一个房子找,费时费力,然后现在加入一个房屋中介,把你需要的房型告诉中介,就可以直接选到需要的房子,中介就相当于spring容器。


    AOP:面向切面编程,是面向对象开发的一种补充,它允许开发人员在不改变原来模型的基础上动态的修改模型以满足新的需求,如:动态的增加日志、安全或异常处理等。AOP使业务逻辑各部分间的耦合度降低,提高程序可重用性,提高开发效率。

    持久层:DAO层(mapper)

    • DAO层:DAO层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,
      • DAO层的设计首先是设计DAO的接口,
      • 然后在Spring的配置文件中定义此接口的实现类,
      • 然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,
      • DAO层的数据源配置,以及有关数据库连接的参数都在Spring的配置文件中进行配置。

    业务层:Service层

    • Service层:Service层主要负责业务模块的逻辑应用设计。
      • 首先设计接口,再设计其实现的类
      • 接着再在Spring的配置文件中配置其实现的关联。这样我们就可以在应用中调用Service接口来进行业务处理。
      • Service层的业务实现,具体要调用到已定义的DAO层的接口,
      • 封装Service层的业务逻辑有利于通用的业务逻辑的独立性和重复利用性,程序显得非常简洁。

    表现层:Controller层(Handler层)

    • Controller层:Controller层负责具体的业务模块流程的控制
      • 在此层里面要调用Service层的接口来控制业务流程,
      • 控制的配置也同样是在Spring的配置文件里面进行,针对具体的业务流程,会有不同的控制器,我们具体的设计过程中可以将流程进行抽象归纳,设计出可以重复利用的子单元流程模块,这样不仅使程序结构变得清晰,也大大减少了代码量。

    View层

    • View层 此层与控制层结合比较紧密,需要二者结合起来协同工发。View层主要负责前台jsp页面的表示.

    各层联系

    • DAO层,Service层这两个层次都可以单独开发,互相的耦合度很低,完全可以独立进行,这样的一种模式在开发大项目的过程中尤其有优势
    • Controller,View层因为耦合度比较高,因而要结合在一起开发,但是也可以看作一个整体独立于前两个层进行开发。这样,在层与层之前我们只需要知道接口的定义,调用接口即可完成所需要的逻辑单元应用,一切显得非常清晰简单。

    • Service逻辑层设计

      • Service层是建立在DAO层之上的,建立了DAO层后才可以建立Service层,而Service层又是在Controller层之下的,因而Service层应该既调用DAO层的接口,又要提供接口给Controller层的类来进行调用,它刚好处于一个中间层的位置。每个模型都有一个Service接口,每个接口分别封装各自的业务处理方法。



    ====================================================================================================================================

       最近在学习Spring+SpringMVC+MyBatis的整合。以下是参考网上的资料自己实践操作的详细步骤。

     

    1、基本概念

     

    1.1、Spring 

            Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

     

    1.2、SpringMVC     

            Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。

     

    1.3、MyBatis

           MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

     

     

    2、开发环境搭建以及创建Maven Web项目

    参看之前的博文:http://www.cnblogs.com/zyw-205520/p/4767633.html

     

    3、SSM整合

     下面主要介绍三大框架的整合,至于环境的搭建以及项目的创建,参看上面的博文。这次整合我分了2个配置文件,分别是spring-mybatis.xml,包含spring和mybatis的配置文件,还有个是spring-mvc的配置文件,此外有2个资源文件:jdbc.propertis和log4j.properties。完整目录结构如下(最后附上源码下载地址):

                                                                            

    使用框架的版本:

           Spring 4.0.2 RELEASE

           Spring MVC 4.0.2 RELEASE

           MyBatis 3.2.6

     

    3.1、Maven引入需要的JAR包

        在pom.xml中引入jar包

    复制代码
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.javen.maven01</groupId>
        <artifactId>maven01</artifactId>
        <packaging>war</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <name>maven01 Maven Webapp</name>
        <url>http://maven.apache.org</url>
        
        <properties>  
            <!-- spring版本号 -->  
            <spring.version>4.0.2.RELEASE</spring.version>  
            <!-- mybatis版本号 -->  
            <mybatis.version>3.2.6</mybatis.version>  
            <!-- log4j日志文件管理包版本 -->  
            <slf4j.version>1.7.7</slf4j.version>  
            <log4j.version>1.2.17</log4j.version>  
        </properties> 
        
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                 <!-- 表示开发的时候引入,发布的时候不会加载此包 -->  
                <scope>test</scope>
            </dependency>
            <!-- <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
            </dependency> -->
            
             <!-- spring核心包 -->  
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-core</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-web</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-oxm</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-tx</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-jdbc</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-webmvc</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-aop</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-context-support</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.springframework</groupId>  
                <artifactId>spring-test</artifactId>  
                <version>${spring.version}</version>  
            </dependency>  
            <!-- mybatis核心包 -->  
            <dependency>  
                <groupId>org.mybatis</groupId>  
                <artifactId>mybatis</artifactId>  
                <version>${mybatis.version}</version>  
            </dependency>  
             <!-- mybatis/spring包 -->  
            <dependency>  
                <groupId>org.mybatis</groupId>  
                <artifactId>mybatis-spring</artifactId>  
                <version>1.2.2</version>  
            </dependency>  
            
             <!-- 导入java ee jar 包 -->  
            <dependency>  
                <groupId>javax</groupId>  
                <artifactId>javaee-api</artifactId>  
                <version>7.0</version>  
            </dependency>  
            
             <!-- 导入Mysql数据库链接jar包 -->  
            <dependency>  
                <groupId>mysql</groupId>  
                <artifactId>mysql-connector-java</artifactId>  
                <version>5.1.36</version>  
            </dependency>  
            <!-- 导入dbcp的jar包,用来在applicationContext.xml中配置数据库 -->  
            <dependency>  
                <groupId>commons-dbcp</groupId>  
                <artifactId>commons-dbcp</artifactId>  
                <version>1.2.2</version>  
            </dependency>  
            
            <!-- JSTL标签类 -->  
            <dependency>  
                <groupId>jstl</groupId>  
                <artifactId>jstl</artifactId>  
                <version>1.2</version>  
            </dependency>  
            <!-- 日志文件管理包 -->  
            <!-- log start -->  
            <dependency>  
                <groupId>log4j</groupId>  
                <artifactId>log4j</artifactId>  
                <version>${log4j.version}</version>  
            </dependency>  
              
              
            <!-- 格式化对象,方便输出日志 -->  
            <dependency>  
                <groupId>com.alibaba</groupId>  
                <artifactId>fastjson</artifactId>  
                <version>1.1.41</version>  
            </dependency>  
      
      
            <dependency>  
                <groupId>org.slf4j</groupId>  
                <artifactId>slf4j-api</artifactId>  
                <version>${slf4j.version}</version>  
            </dependency>  
      
            <dependency>  
                <groupId>org.slf4j</groupId>  
                <artifactId>slf4j-log4j12</artifactId>  
                <version>${slf4j.version}</version>  
            </dependency>  
            <!-- log end -->  
            <!-- 映入JSON -->  
            <dependency>  
                <groupId>org.codehaus.jackson</groupId>  
                <artifactId>jackson-mapper-asl</artifactId>  
                <version>1.9.13</version>  
            </dependency>  
            <!-- 上传组件包 -->  
            <dependency>  
                <groupId>commons-fileupload</groupId>  
                <artifactId>commons-fileupload</artifactId>  
                <version>1.3.1</version>  
            </dependency>  
            <dependency>  
                <groupId>commons-io</groupId>  
                <artifactId>commons-io</artifactId>  
                <version>2.4</version>  
            </dependency>  
            <dependency>  
                <groupId>commons-codec</groupId>  
                <artifactId>commons-codec</artifactId>  
                <version>1.9</version>  
            </dependency>  
    
        </dependencies>
        
        <build>
            <finalName>maven01</finalName>
            <plugins>
                <plugin>
                    <groupId>org.eclipse.jetty</groupId>
                    <artifactId>jetty-maven-plugin</artifactId>
                    <version>9.2.8.v20150217</version>
                    <configuration>
                        <httpConnector>
                            <port>80</port>
                        </httpConnector>
                        <stopKey>shutdown</stopKey>
                        <stopPort>9966</stopPort>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    </project>
    复制代码

    3.2、整合SpringMVC

    3.2.1、配置spring-mvc.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">  
        <!-- 自动扫描该包,使SpringMVC认为包下用了@controller注解的类是控制器 -->  
        <context:component-scan base-package="com.javen.controller" />  
        <!-- 扩充了注解驱动,可以将请求参数绑定到控制器参数 -->
        <mvc:annotation-driven/>
        <!-- 静态资源处理  css js imgs -->
        <mvc:resources location="/resources/**" mapping="/resources"/>
        
        <!--避免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>  
        <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->  
        <bean  
            class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
            <property name="messageConverters">  
                <list>  
                    <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON转换器 -->  
                </list>  
            </property>  
        </bean>  
          
        <!-- 配置文件上传,如果没有使用文件上传可以不用配置,当然如果不配,那么配置文件中也不必引入上传组件包 -->  
        <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" />    
            <!-- 启用是为了推迟文件解析,以便捕获文件大小异常 -->
            <property name="resolveLazily" value="true"/>
        </bean>   
        
        <!-- 配置ViewResolver 。可用多个ViewResolver 。使用order属性排序。   InternalResourceViewResolver 放在最后-->
        <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
        <property name="order" value="1"></property>
            <property name="mediaTypes">
                <map>
                    <!-- 告诉视图解析器,返回的类型为json格式 -->
                    <entry key="json" value="application/json" />
                    <entry key="xml" value="application/xml" />
                    <entry key="htm" value="text/htm" />
                </map>
            </property>
            <property name="defaultViews">
                <list>
                    <!-- ModelAndView里的数据变成JSON -->
                    <bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
                </list>
            </property>
            <property name="ignoreAcceptHeader" value="true"></property>
        </bean>
        
       <!-- 定义跳转的文件的前后缀 ,视图模式配置-->  
        <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
            <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->  
            <property name="prefix" value="/WEB-INF/jsp/" />  
            <property name="suffix" value=".jsp" />  
        </bean>  
    </beans>  
    复制代码

     

    3.2.2、配置web.xml文件

     配置的spring-mvc的Servlet就是为了完成SpringMVC+MAVEN的整合。

    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>Archetype Created Web Application</display-name>  
        <!-- Spring和mybatis的配置文件 -->  
       <!--  <context-param>  
            <param-name>contextConfigLocation</param-name>  
            <param-value>classpath:spring-mybatis.xml</param-value>  
        </context-param>   -->
        <!-- 编码过滤器 -->  
        <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>  
        <!-- Spring监听器 -->  
       <!--  <listener>  
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
        </listener>   -->
        <!-- 防止Spring内存溢出监听器 -->  
        <!-- <listener>  
            <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>  
        </listener>  --> 
      
        <!-- 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>  
            <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->  
            <url-pattern>/</url-pattern>  
        </servlet-mapping>  
        <welcome-file-list>  
            <welcome-file>/index.jsp</welcome-file>  
        </welcome-file-list>  
      
    </web-app>  
    复制代码

     

     

    3.2.3、Log4j的配置

       为了方便调试,一般都会使用日志来输出信息,Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。

     

          Log4j的配置很简单,而且也是通用的,下面给出一个基本的配置,换到其他项目中也无需做多大的调整,如果想做调整或者想了解Log4j的各种配置,参看我转载的一篇博文,很详细:http://blog.csdn.net/zhshulin/article/details/37937365

    下面给出配置文件目录:

     

    log4j.properties

    复制代码
    log4j.rootLogger=INFO,Console,File  
    #定义日志输出目的地为控制台  
    log4j.appender.Console=org.apache.log4j.ConsoleAppender  
    log4j.appender.Console.Target=System.out  
    #可以灵活地指定日志输出格式,下面一行是指定具体的格式  
    log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
    log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n  
      
    #文件大小到达指定尺寸的时候产生一个新的文件  
    log4j.appender.File = org.apache.log4j.RollingFileAppender  
    #指定输出目录  
    log4j.appender.File.File = logs/ssm.log  
    #定义文件最大大小  
    log4j.appender.File.MaxFileSize = 10MB  
    # 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志  
    log4j.appender.File.Threshold = ALL  
    log4j.appender.File.layout = org.apache.log4j.PatternLayout  
    log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n  
    复制代码

     

     

    3.2.4、使用Jetty测试

     

     

    复制代码
    package com.javen.model;
    
    public class User {
        private Integer id;
    
        private String userName;
    
        private String password;
    
        private Integer age;
    
        public Integer getId() {
            return id;
        }
    
        public void setId(Integer id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName == null ? null : userName.trim();
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password == null ? null : password.trim();
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User [id=" + id + ", userName=" + userName + ", password="
                    + password + ", age=" + age + "]";
        }
        
        
    }
    复制代码
    复制代码
    package com.javen.controller;
    import javax.servlet.http.HttpServletRequest;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Controller;  
    import org.springframework.ui.Model;  
    import org.springframework.web.bind.annotation.RequestMapping;  
    import org.springframework.web.bind.annotation.RequestMethod;
    import com.javen.model.User;
      
      
    @Controller  
    @RequestMapping("/user")  
    // /user/**
    public class UserController {  
        private static Logger log=LoggerFactory.getLogger(UserController.class);
          
        
        // /user/test?id=1
        @RequestMapping(value="/test",method=RequestMethod.GET)  
        public String test(HttpServletRequest request,Model model){  
            int userId = Integer.parseInt(request.getParameter("id"));  
            System.out.println("userId:"+userId);
            User user=null;
            if (userId==1) {
                 user = new User();  
                 user.setAge(11);
                 user.setId(1);
                 user.setPassword("123");
                 user.setUserName("javen");
            }
           
            log.debug(user.toString());
            model.addAttribute("user", user);  
            return "index";  
        }  
    }  
    复制代码

     

     

                                   

     

    在浏览器中输入:http://localhost/user/test?id=1

    到此 SpringMVC+Maven 整合完毕

     

     

     


    3.3 Spring与MyBatis的整合

       取消3.2.2 web.xml中注释的代码 

     

     

    3.3.1、建立JDBC属性文件

     

     

     

    jdbc.properties(文件编码修改为utf-8)

    复制代码
    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/maven
    username=root
    password=root
    #定义初始连接数  
    initialSize=0  
    #定义最大连接数  
    maxActive=20  
    #定义最大空闲  
    maxIdle=20  
    #定义最小空闲  
    minIdle=1  
    #定义最长等待时间  
    maxWait=60000  
    复制代码

    此时的目录结构为 

     

     

                                                                  

    3.3.2、建立spring-mybatis.xml配置文件

        这个文件就是用来完成spring和mybatis的整合的。这里面也没多少行配置,主要的就是自动扫描,自动注入,配置数据库。注释也很详细,大家看看就明白了。

    spring-mybatis.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">  
        <!-- 自动扫描 -->  
        <context:component-scan base-package="com.javen" />  
        
        <!-- 引入配置文件 -->  
        <bean id="propertyConfigurer"  
            class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
            <property name="location" value="classpath:jdbc.properties" />  
        </bean>  
      
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
            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/javen/mapping/*.xml"></property>  
        </bean>  
      
        <!-- DAO接口所在包名,Spring会自动查找其下的类 -->  
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
            <property name="basePackage" value="com.javen.dao" />  
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
        </bean>  
      
        <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->  
        <bean id="transactionManager"  
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
            <property name="dataSource" ref="dataSource" />  
        </bean>  
      
    </beans>  
    复制代码

    3.4、JUnit测试

      经过以上步骤,我们已经完成了Spring和mybatis的整合,这样我们就可以编写一段测试代码来试试是否成功了。

     

    3.4.1、创建测试用表

    既然我们需要测试,那么我们就需要建立在数据库中建立一个测试表,这个表建的很简单,SQL语句为:

    复制代码
    -- ----------------------------
    -- Table structure for `user_t`
    -- ----------------------------
    DROP TABLE IF EXISTS `user_t`;
    CREATE TABLE `user_t` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `user_name` varchar(40) NOT NULL,
      `password` varchar(255) NOT NULL,
      `age` int(4) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user_t
    -- ----------------------------
    INSERT INTO `user_t` VALUES ('1', '测试', '345', '24');
    INSERT INTO `user_t` VALUES ('2', 'javen', '123', '10');
    复制代码

     

    3.4.2、利用MyBatis Generator自动创建代码

     

    参考博文:http://blog.csdn.net/zhshulin/article/details/23912615

     

     这个可根据表自动创建实体类、MyBatis映射文件以及DAO接口,当然,我习惯将生成的接口名改为IUserDao,而不是直接用它生成的UserMapper。如果不想麻烦就可以不改。完成后将文件复制到工程中。如图:

                                                                      

    3.4.3、建立Service接口和实现类

                                                                     

    下面给出具体的内容:

    IUserService.jave

    复制代码
    package com.javen.service;  
    
    import com.javen.model.User;
      
      
    public interface IUserService {  
        public User getUserById(int userId);  
    }  
    复制代码

    UserServiceImpl.java

    复制代码
    package com.javen.service.impl;
    import javax.annotation.Resource;  
    
    import org.springframework.stereotype.Service;  
    import com.javen.dao.IUserDao;
    import com.javen.model.User;
    import com.javen.service.IUserService;
      
      
    @Service("userService")  
    public class UserServiceImpl implements IUserService {  
        @Resource  
        private IUserDao userDao;  
        
        public User getUserById(int userId) {  
            // TODO Auto-generated method stub  
            return this.userDao.selectByPrimaryKey(userId);  
        }  
      
    }  
    复制代码

     

     

    3.4.4、建立测试类

     测试类在src/test/java中建立,下面测试类中注释掉的部分是不使用Spring时,一般情况下的一种测试方法;如果使用了Spring那么就可以使用注解的方式来引入配置文件和类,然后再将service接口对象注入,就可以进行测试了。

           如果测试成功,表示Spring和Mybatis已经整合成功了。输出信息使用的是Log4j打印到控制台。

     

    复制代码
    package com.javen.testmybatis;
    
    import javax.annotation.Resource;  
    
    import org.apache.log4j.Logger;  
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;  
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
    import com.alibaba.fastjson.JSON;  
    import com.javen.model.User;
    import com.javen.service.IUserService;
      
    @RunWith(SpringJUnit4ClassRunner.class)     //表示继承了SpringJUnit4ClassRunner类  
    @ContextConfiguration(locations = {"classpath:spring-mybatis.xml"})  
      
    public class TestMyBatis {  
        private static Logger logger = Logger.getLogger(TestMyBatis.class);  
    //  private ApplicationContext ac = null;  
        @Resource  
        private IUserService userService = null;  
      
    //  @Before  
    //  public void before() {  
    //      ac = new ClassPathXmlApplicationContext("applicationContext.xml");  
    //      userService = (IUserService) ac.getBean("userService");  
    //  }  
      
        @Test  
        public void test1() {  
            User user = userService.getUserById(1);  
            // System.out.println(user.getUserName());  
            // logger.info("值:"+user.getUserName());  
            logger.info(JSON.toJSONString(user));  
        }  
    }  
    复制代码

    测试结果 

     

    3.4.5、建立UserController类

    UserController.java  控制器   

     

    复制代码
    package com.javen.controller;
    import java.io.File;
    import java.io.IOException;
    import java.util.Map;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.io.FileUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.stereotype.Controller;  
    import org.springframework.ui.Model;  
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;  
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;
    import org.springframework.web.multipart.MultipartFile;
    
    import com.javen.model.User;
    import com.javen.service.IUserService;
      
      
    @Controller  
    @RequestMapping("/user")  
    // /user/**
    public class UserController {  
        private static Logger log=LoggerFactory.getLogger(UserController.class);
         @Resource  
         private IUserService userService;     
        
        // /user/test?id=1
        @RequestMapping(value="/test",method=RequestMethod.GET)  
        public String test(HttpServletRequest request,Model model){  
            int userId = Integer.parseInt(request.getParameter("id"));  
            System.out.println("userId:"+userId);
            User user=null;
            if (userId==1) {
                 user = new User();  
                 user.setAge(11);
                 user.setId(1);
                 user.setPassword("123");
                 user.setUserName("javen");
            }
           
            log.debug(user.toString());
            model.addAttribute("user", user);  
            return "index";  
        }  
        
        
        // /user/showUser?id=1
        @RequestMapping(value="/showUser",method=RequestMethod.GET)  
        public String toIndex(HttpServletRequest request,Model model){  
            int userId = Integer.parseInt(request.getParameter("id"));  
            System.out.println("userId:"+userId);
            User user = this.userService.getUserById(userId);  
            log.debug(user.toString());
            model.addAttribute("user", user);  
            return "showUser";  
        }  
        
     // /user/showUser2?id=1
        @RequestMapping(value="/showUser2",method=RequestMethod.GET)  
        public String toIndex2(@RequestParam("id") String id,Model model){  
            int userId = Integer.parseInt(id);  
            System.out.println("userId:"+userId);
            User user = this.userService.getUserById(userId);  
            log.debug(user.toString());
            model.addAttribute("user", user);  
            return "showUser";  
        }  
        
        
        // /user/showUser3/{id}
        @RequestMapping(value="/showUser3/{id}",method=RequestMethod.GET)  
        public String toIndex3(@PathVariable("id")String id,Map<String, Object> model){  
            int userId = Integer.parseInt(id);  
            System.out.println("userId:"+userId);
            User user = this.userService.getUserById(userId);  
            log.debug(user.toString());
            model.put("user", user);  
            return "showUser";  
        }  
        
     // /user/{id}
        @RequestMapping(value="/{id}",method=RequestMethod.GET)  
        public @ResponseBody User getUserInJson(@PathVariable String id,Map<String, Object> model){  
            int userId = Integer.parseInt(id);  
            System.out.println("userId:"+userId);
            User user = this.userService.getUserById(userId);  
            log.info(user.toString());
            return user;  
        }  
        
        // /user/{id}
        @RequestMapping(value="/jsontype/{id}",method=RequestMethod.GET)  
        public ResponseEntity<User>  getUserInJson2(@PathVariable String id,Map<String, Object> model){  
            int userId = Integer.parseInt(id);  
            System.out.println("userId:"+userId);
            User user = this.userService.getUserById(userId);  
            log.info(user.toString());
            return new ResponseEntity<User>(user,HttpStatus.OK);  
        } 
        
        //文件上传、
        @RequestMapping(value="/upload")
        public String showUploadPage(){
            return "user_admin/file";
        }
        
        @RequestMapping(value="/doUpload",method=RequestMethod.POST)
        public String doUploadFile(@RequestParam("file")MultipartFile file) throws IOException{
            if (!file.isEmpty()) {
                log.info("Process file:{}",file.getOriginalFilename());
            }
            FileUtils.copyInputStreamToFile(file.getInputStream(), new File("E:\\",System.currentTimeMillis()+file.getOriginalFilename()));
            return "succes";
        }
    }  
    复制代码

     

    3.4.6、新建jsp页面

    file.jsp

    复制代码
    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="utf-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Insert title here</title>
    </head>
    <body>
        <h1>上传文件</h1>
        <form method="post" action="/user/doUpload" enctype="multipart/form-data">
            <input type="file" name="file"/>
            <input type="submit" value="上传文件"/>
            
        </form>
    </body>
    </html>
    复制代码

    index.jsp

    <html>
    <body>
    <h2>Hello World!</h2>
    </body>
    </html>

    showUser.jsp

    复制代码
    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>  
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  
    <html>  
      <head>  
        <title>测试</title>  
      </head>  
        
      <body>  
        ${user.userName}  
      </body>  
    </html>  
    复制代码

     

    至此,完成Spring+SpingMVC+mybatis这三大框架整合完成。

     

    3.4.7、部署项目

     

    输入地址:http://localhost/user/jsontype/2

      项目下载地址:https://github.com/Javen205/SSM

     

        参考博客:http://blog.csdn.net/gebitan505/article/details/44455235


    展开全文
  • SEAndroid安全机制框架分析

    万次阅读 多人点赞 2014-07-14 01:00:02
    针对传统Linux系统,NSA开发了一套安全机制SELinux,用来加强安全性。然而,由于Android系统有着独特的用户空间运行时,因此SELinux不能完全适用于Android系统。为此,NSA针对Android系统,在SELinux基础上开发了...
  • 安全框架 Shiro 和 Spring Security 如何选择?

    万次阅读 多人点赞 2019-09-26 14:39:46
    点击上方"程序员的成长之路",选择"置顶或星标"你关注就是我关心的!安全框架安全框架,简单说是对访问权限进行控制,应用的安全性包括用户认证(Authentication)...
  • 在SpringBoot 中使用Security安全框架

    万次阅读 多人点赞 2019-04-25 14:24:08
    网上有很多关于SpringBoot中使用SpringSecurity安全框架的教程,但是都是讲的不够清晰易懂,首先来讲,为什么我们要使用SpringSecurity,以前没有这个框架的时候,我们要想实现权限页面拦截,都采用的拦截器(interceptor)...
  • MobSF移动安全检测框架简述

    千次阅读 2017-03-24 14:08:04
    移动安全分析框架 (MobSF) 是一个智能的、集成型的、开源移动App(安卓/iOS)自动检测框架,能用于静态检测和动态检测。该框架可以进行高效迅速的移动应用安全分析。文章将介绍MobSF的使用指南和检测项目,并对框架...
  • 安全认证框架Shiro (二)- shiro过滤器工作原理

    万次阅读 多人点赞 2017-11-15 17:27:48
    安全认证框架Shiro (二)- shiro过滤器工作原理 安全认证框架Shiro 二- shiro过滤器工作原理 第一前言 第二ShiroFilterFactoryBean入口 第三请求到来解析过程 第四过滤器执行原理 第五总结第一:前言由于工作原因,...
  • 网络信息安全知识框架

    万次阅读 多人点赞 2018-12-30 22:10:32
    如需要下列知识的详细内容,欢迎评论或私信联系我。 第0章 基础概述 1.网络信息安全的原则(包括...1.1 网络安全的概念 (信息安全的4个层面、信息安全所涉及学科、研究信息安全的重要性、网络安全的概念) 1.2 ...
  • 第四章 Android 框架层安全 来源:Yury Zhauniarovich | Publications 译者:飞龙 协议:CC BY-NC-SA 4.0 如我们在第1.2节中所描述的那样,应用程序框架级别上的安全性由 IPC 引用监视器实现。 在 4.1 节中,...
  • Struts2框架安全缺陷

    万次阅读 2013-07-19 15:56:37
    本文介绍了java开发流行框架struts2以及webwork的一些安全缺陷,并举例说明框架本身以及开发人员使用框架时,所产生的种种安全问题,以及作者挖掘框架安全漏洞的一些心得体会。 推荐以下人群阅读 了解java开发 ...
  • Apache Shiro安全框架(1)-整体功能介绍

    千次阅读 2018-06-16 14:37:41
    Apche shiro是Java的常用安全框架之一,也是目前Java使用最多的安全框架。主要的核心功能包括:认证、授权、会话管理、加密。也提供了额外的功能支持在不同环境所关注的问题。例如:支持web的API、缓存、记住用户...
  • Shiro笔记(一)----Shiro安全框架简介

    万次阅读 多人点赞 2017-02-14 09:57:33
    功能强大,使用简单的Java安全框架,它为开发人员提供一个直观而全面的认证,授权,加密及会话管理的解决方案。 实际上,Shiro的主要功能是管理应用程序中与安全相关的全部,同时尽可能支持多种实现方法。Shiro是...
  • 从这些标准和框架中,我们能了解到建设安全体系的思路和方向,对于实际的安全落地工作,有很大的指导作用。 根据安全等级和关注点的不同,不同的安全标准和框架都有各自的具体要求。这些要求都非常简单直接,也很...
  • 初识Spring Boot框架

    万次阅读 多人点赞 2016-12-19 20:42:04
    刚刚说的这种方式我们在实际项目中使用的时候工作量略大,因为每个项目要注入的变量的值太多了,这种时候我们可以使用基于类型安全的配置方式,就是将properties属性和一个Bean关联在一起,这样使用起来会更加方便。...
  • 安全框架Apache Shiro学习心得

    万次阅读 2012-07-23 13:49:34
     2) successUrl和unauthorizedUrl调试时曾经没有起作用,后来莫名其妙好了,原因不明,可能是开始代码或配置有问题,比如:为了测试权限注解,在login Action里调用了一个加上了@RequiresPermissions("account:...
  • Secure Boot 这个功能负责在SOC启动时验证bootloader二进制的合法性。Bootloader二进制是由SOC的Rom Code启动的,所以这个bootloader的合法性认证就需要由Rom Code来实现,那bootloader认证使用的公钥保存在哪里呢?...
  • trustzone的硬件框架和安全扩展

    千次阅读 热门讨论 2017-06-03 21:43:43
    历经一年多时间的系统整理合补充,《手机安全和可信应用开发指南:TrustZone与OP-TEE技术详解 》一书得以出版,书中详细介绍了TEE以及系统安全中的所有内容,全书按照从硬件到软件,从用户空间到内核空间的顺序对TEE...
  • 经典Web安全缺陷(框架钓鱼风险)

    千次阅读 2016-09-17 09:32:37
    1、概述:Web安全应用程序的安全始终是一个重要的议题,因为网站是恶意工作者的第一目标。黑客利用网络传播其恶意软件、蠕虫、垃圾及其他等等。QWASP(是一个符合501(c)3)全球不以营利为目的的慈善组织专注于提高...
  • 深入理解Spring框架的作用

    万次阅读 多人点赞 2018-02-20 20:15:24
    装配的作用就是创建类的实例,同时将类的构造函数或者setter函数参数设置好,这是为了配置对象和对象之间的关系。 在这里, BraveKnight和SlayDragonQuest被声明为Spring中的bean。 就BraveKnight bean来讲, ...
  • shiro框架提供了验证、授权、加密、会话管理等常用的安全功能,而且使用POJO式的API使得该框架能部署在大多数的环境中,此外还针对不同的情形提供了各种API实现,在数据存储上,其开放式的API使得我们在不同数据环境...
  • shiro安全框架---shiro的应用理解

    千次阅读 2018-02-13 16:36:42
      shiro是一个apache开发的一个安全框架,用来管理我们开发系统中的用户登录、权限授权、会话管理等的。通俗一点就是,如果你想让你开发的系统有用户登录功能、根据不同用户登陆进系统有不一样的功能,并且能够...
  • 关于单例bean的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的Spring bean并没有可变的状态(比如Serview类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话...
  • ThreadLocal在spring框架中的作用

    千次阅读 2009-01-15 10:49:00
    这些模板类都是线程安全的,也就是说,多个DAO能够复用同一个模板实例而不会发生冲突。 我们使用模板类访问底层数据,根据持久化技术的不同,模板类需要绑定数据连接或会话的资源。但这些资源本身是非线程安全的,也...
  • 选择方式 如果你还想要安全过滤器链起作用。 如果你希望使用基本认证,代替表单登录,可以把配置改为: **" access="ROLE_USER" /> 基本身份认证会被优先用到,在用户尝试访问一个受保护的资源时,用来...
  • Spring作用域(scope)的配置区别: 非线程安全:Singleton(默认): Spring容器只存在一个共享的bean实例。 线程安全: Prototype: 每次对bean的请求都会创建一个新的bean实例。 使用实例: DAO层的实现类...
  • 前言本系列前面的文章说过,为了某信息安全比赛,我选了一个APK行为分析的题目。之前一直在研究安卓的编程,然后看了一下关于apk分析方面的书,觉得完全没有目标,不知道如何下手,偶然间在freebuf闲逛的时候,随手...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 281,283
精华内容 112,513
关键字:

安全框作用