• 深入理解java:4. 框架编程


    了解 Servlet 和 Filter

    Servlet(即servlet-api.jar) 是 J2EE 最重要的一部分,有了 Servlet 你就是 J2EE 了,J2EE 的其他方面的内容择需采用。

    而 Servlet 规范你需要掌握的就是 servlet 和 filter 这两项技术。

    绝大多数框架不是基于 servlet 就是基于 filter,如果它要在 Servlet 容器上运行,就永远也脱离不开这个模型。

    Servlet容器,大一点就是应用服务器,推荐 Tomcat 、或者 Jetty 这些轻量级的产品。

    SpringMVC的入口是servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层。
    Struts2的入口是filter:filter是一个可以复用的代码片段,可以用来转换HTTP请求、响应和头信息。Filter不像Servlet,它不能产生一个请求或者响应,它只是修改对某一资源的请求,或者修改从某一的响应。filter能够在一个请求到达servlet之前预处理用户请求,也可以在离开servlet时处理http响应。

    为什么 Servlet 规范会有两个包,javax.servlet 和 javax.servlet.http ?

    早先设计该规范的人认为 Servlet 是一种服务模型,不一定是依赖某种网络协议之上,因此就抽象出了一个 javax.servlet ,同时再提供一个基于 HTTP 协议上的接口扩展。

    但是从实际运行这么多年来看,似乎没有发现有在其他协议上实现的 Servlet 技术。

    javax.servlet 和 javax.servlet.http 这两个包总共加起来也不过是三十四个接口和类。你需要通过 J2EE 的 JavaDoc 文档 熟知每个类和接口的具体意思。

    特别是下面几个接口必须熟知每个方法的意思和用途:

    • HttpServlet
    • ServetConfig
    • ServletContext
    • Filter
    • FilterConfig
    • FilterChain
    • RequestDispatcher
    • HttpServletRequest
    • HttpServletResponse
    • HttpSession
    • 一些 Listenser 类

    再次强调 HttpServletRequestHttpServletResponse 这两个接口更应该是烂熟于心。

    因为 Web 开发是离不开 HTTP 协议的,而 Servlet 规范其实就是对 HTTP 协议做面向对象的封装,HTTP协议中的请求和响应就是对应了 HttpServletRequest 和 HttpServletResponse 这两个接口。

    你可以通过 HttpServletRequest 来获取所有请求相关的信息,包括 URI、Cookie、Header、请求参数等等,别无它路。

    因此当你使用某个框架时,你想获取HTTP请求的相关信息,只要拿到 HttpServletRequest 实例即可。

    再谈谈 Session

    HTTP 协议里是没有关于 Session 会话的定义,Session 是各种编程语言根据 HTTP 协议的无状态这种特点而产生的。

    其实现无非就是服务器端的一个哈希表,哈希表的Key就是传递给浏览器的名为 jsessionid 的 Cookie 值。

    当需要将某个值保存到 session 时,容器会执行如下几步:

    a. 获取 jsessionid 值,没有的话就生成一个,也就是 request.getSession() 这个方法
    b. 拿到的 HttpSession 对象实例就相当于一个哈希表,你可以往哈希表里存放数据(setAttribute)
    c. 你也可以通过 getAttribute 来获取某个值

    而这个名为 jsessionid 的 Cookie 在浏览器关闭时会自动删除。

    把 Cookie 的 MaxAge 值设为 -1 就能达到浏览器关闭自动删除的效果。

    关于 JSP

    任何一个 JSP 页面在执行的时候都会编译成一个 Servlet 类文件,

    如果是 Tomcat 的话,这些生成的 java 文件会放置在 {TOMCAT}/work 目录下对应项目的子目录中。

    在 servlet 中有一个包 javax.servlet.jsp 是跟 JSP 相关的一些接口规范定义。

    JSP 比 Servlet 方便的地方在于可直接修改立即生效,不像 Servlet 修改后必须重启容器才能生效。

    因此 JSP 适合用来做视图,而 Servlet 则适合做控制层。

    struts不过是对servlet、filter的封装而已,

    hibernate也不过是对jdbc的封装而已。

    框架解决的是解耦的问题,复用的问题,分工的问题。

    SSI框架总结

    专注于控制层的Struts2

    专注于业务逻辑方面的spring框架

    专注于持久层的 iBatis

    Struts2主要来源于webwork框架,在数据传递方面,Struts2提供了更加强大OGNL标签功能,使其能够通过在action中定义变量来直接与jsp页面中的数据进行相互传值,省去了Struts1中的formbean。

    Spring功能非常的强大,比如它的控制反转/依赖注入机制,省去了我们自己书写工厂模式的工作;Spring对AOP支持使我们在用户权限控制、事务处理方面节省了很多工作量;

    iBatis则是一种轻量级的ORM框架,与Hibernate相比,iBatis提供了半自动化对象关系 映射的实现,开发人员需要编写具体的sql语句,提供了更大的自由空间,为sql语句优化提供了便利。

    下面这张图就是我们所用到的这三种框架的结合体,下面对其作以简单介绍。

     


    在控制层,利用Strtus2标签功能,在Action中直接与jsp页面上的数据进行交互。

    在调用业务逻辑层应用时,Struts2提供了对Sping的支持。

    开发人员需要完成对struts.xml的配置工作和对各个Action类的编写。

     

    在业务逻辑层,利用Spring框架的依赖注入实现对业务逻辑类和DAO类的实例托管;

    在事务处理方面,利用Spring提供的面向切面的事务处理功能,使对数据的事务控制脱离于数据访问接口实现;

    在对象关系映射方面,利用Spring对数据库连接池的托管和对iBatis框架的支持。

    开发人员需要完成对数据源的配置、对不同模块所对应的Application*.xml文件的配置,以及对业务逻辑接口的定义和业务逻辑实现的编写。

     

    在持久层,利用iBatis提供的半自动化对象关系映射的实现,开发人员需要编写具体的sql语句,为系统设计提供了更大的自由空间。

    另外,开发人员需要完成对SqlMapConfig.xml和*SqlMap.xml的配置,以及对DAO接口的定义和DAO接口的实现。

     

    在各层之间进行交换的过程中,利用数据传输类进行数据的传递和交互。其中,数据传输类与数据库表一一对应。

    SSI框架能够降低我们代码的耦合度,增强了代码的健壮性和可重用性,加快了开发速度,

    但是也有一些不足之处,比如由于三种框架的配置文件较多,也给我们带来了一些不便,特别是对于较小的应用来说更是如此。

     

    SSI开发过程:

    一:首先引入struts2 spring ibatis 各自的jar包 在此就不一一罗列了。

    二:添加配置文件

       我们首先从web.xml文件说起

       web.xml加载过程:
       1 启动WEB项目的时候,容器(如:Tomcat)会读他的配置文件web.xml读两个节点
             <context-param></context-param>和<listener></listener>
        2 紧接着,容器创建一个ServletContext(上下文) 这个WEB项目所有部分都将共享这个上下文
        3 容器将<context-param></context-param>转化为键值对并交给ServletContext
        4 容器创建<listener></listener>中的类的实例,即创建监听
        5 在监听中会有contextInitialized(ServletContextEvent args)初始化方法,在这个方法中获得:
                  ServletContext = ServletContextEvent.getServletContext();  
                  context-param的 = ServletContext.getInitParameter("context-param的");

         web.xml节点加载顺序
         节点的加载顺序与它们在web.xml文件中的先后顺序无关。即不会因为filter写在listener的前面而会先加载filter。

         最终得出的结论是:listener->filter->servlet
         同时还存在着这样一种配置节点:context-param,它用于向 ServletContext 提供键值对,即应用程序上下文信息。

         我们的 listener, filter 等在初始化时会用到这些上下文 的信息,那么context-param 配置节是不是应该写在 listener 配置节前呢?实际上 context-param 配置节可写在任意位置,因此真正的加载顺序为:
         context-param -> listener -> filter -> servlet

        加载spring
         <listener> 
                 <listener-class> 
                   org.springframework.web.context.ContextLoaderListener  
                </listener-class> 
           </listener>
         最终结论:

         web.xml 的加载顺序是:[context-param -> listener -> filter -> servlet -> spring] ,而同类型节点之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺序进行调  用的。

        打开web.xml文件,根据实际需要添加如下内容

    <!--上下文参数用于log4j以及spring中使用-->
    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>/WEB-INF/log4j.properties</param-value>
    </context-param>
    
    <!--应用程序上下文参数,指定spring配置文件位置-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/beans.xml</param-value>
    </context-param> 
    
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>
    
    <!--监听器 用于初始化spring框架-->
    <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

     
    在这说说SSI整合时的一些配置文件:

     1,contextConfigLocation:Spring容器启动时需要加载Spring的配置文件。默认是/WEB-INF目录下的applicationContext.xml文件

       当然也可以放在classpath下,可以包括多个spring配置文件,这就得依靠contextConfigLocation

    <!-- 加载spring的配置文件 如果文件名为applicationContext.xml并且是在WEB-INF目录下 则无需此配置 -->
        <context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>/WEB-INF/beans.xml</param-value>
        </context-param> 

    如果web.xml中没有配置context-param,spring的配置就像如上这段代码示例一下,自动去WEB-INF目录下寻找applicationContext.xml。此时,如果你修改applicationContext.xml的名称,或者移除它,再启动服务器,你会得到如下异常信息:

    1.nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/WEB-INF/applicationContext.xml]  
    

    这证实了其默认配置。默认配置情况下spring只会去WEB-INF目录下寻找配置文件,而不会去classpath下寻找。
    如果我们不想将配置文件放在WEB-INF目录下呢?开发中经常在src下面创建一个config目录,用于存放配置文件。此时,对应的param-value改为:classpath:config/applicationContext.xml。
    一定要加上classpath,这告诉spring去class目录下的config目录下面寻找配置文件。

    2,如何启动Spring容器

    两种方法,一种以listener启动  一种以load-on-startup Servlet。

    <!-- 配置spring监听器 -->
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>

     

    第二种

    <servlet>
     <servlet-name>context</servlet-name>
     <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
     <load-on-startup>1</load-on-startup>
    </servlet>
    
    
     

     

     3,整合Struts2

            <filter>
    		<filter-name>struts2</filter-name>
    		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>struts2</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>


    4,Spring整合ibatis配置文件

           <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
    		<property name="configLocation"> 
    			<value>classpath:SqlMapConfig.xml</value>
    		</property>
    	</bean>
    

    5,Struts.xml

    <constant name="struts.objectFactory" value="spring" />

    constant配置struts的常量(也可在struts.properties)文件中配置,将struts的对象工厂托由spring管理。

    SSM框架总结

    SpringMVC可以完全替代Struts,配合注解的方式,编程非常快捷,而且通过restful风格定义url,让地址看起来非常优雅。
    另外,MyBatis也可以替换hibernate,正因为MyBatis的半自动特点,我们程序猿可以完全掌控SQL,这会让有数据库经验的程序猿能开发出高效率的SQL语句,而且XML配置管理起来也非常方便。

    1. SpringMVC:它用于web层,相当于controller(等价于传统的servlet和struts的action),用来处理用户请求。举个例子,用户在地址栏输入http://网站域名/login,那么springmvc就会拦截到这个请求,并且调用controller层中相应的方法,(中间可能包含验证用户名和密码的业务逻辑,以及查询数据库操作,但这些都不是springmvc的职责),最终把结果返回给用户,并且返回相应的页面(当然也可以只返回json/xml等格式数据)。springmvc就是做前面和后面过程的活,与用户打交道!!

    2. spring:太强大了,以至于我无法用一个词或一句话来概括它。但与我们平时开发接触最多的估计就是IOC容器,它可以装载bean,有了这个机制,我们就不用在每次使用这个类的时候为它初始化,很少看到关键字new。另外spring的aop,事务管理等等都是我们经常用到的。

    3. MyBatis:如果你问我它跟鼎鼎大名的Hibernate有什么区别?我只想说,他更符合我的需求。第一,它能自由控制sql,这会让有数据库经验的人编写的代码能搞提升数据库访问的效率。第二,它可以使用xml的方式来组织管理我们的sql,因为一般程序出错很多情况下是sql出错,别人接手代码后能快速找到出错地方,甚至可以优化原来写的sql。

    SpringMVC与Struts2区别与比较总结

    1、Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上SpringMVC就容易实现restful url,而struts2的架构实现起来要费劲,因为Struts2中Action的一个方法可以对应一个url,而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了。

    2、由上边原因,SpringMVC的方法之间基本上独立的,独享request response数据,请求数据通过参数获取,处理结果通过ModelMap交回给框架,方法之间不共享变量,而Struts2搞的就比较乱,虽然方法之间也是独立的,但其所有Action变量是共享的,这不会影响程序运行,却给我们编码 读程序时带来麻烦,每次来了请求就创建一个Action,一个Action对象对应一个request上下文。
    3、由于Struts2需要针对每个request进行封装,把request,session等servlet生命周期的变量封装成一个Map,供给每个Action使用,并保证线程安全,所以在原则上,是比较耗费内存的。

    4、 拦截器实现机制上,Struts2有以自己的interceptor机制,SpringMVC用的是独立的AOP方式,这样导致Struts2的配置文件量还是比SpringMVC大。

    5、SpringMVC的入口是servlet,而Struts2是filter(这里要指出,filter和servlet是不同的。以前认为filter是servlet的一种特殊),这就导致了二者的机制不同,这里就牵涉到servlet和filter的区别了。

    6、SpringMVC集成了Ajax,使用非常方便,只需一个注解@ResponseBody就可以实现,然后直接返回响应文本即可,而Struts2拦截器集成了Ajax,在Action中处理时一般必须安装插件或者自己写代码集成进去,使用起来也相对不方便。

    7、SpringMVC验证支持JSR303,处理起来相对更加灵活方便,而Struts2验证比较繁琐,感觉太烦乱。

    8、spring MVC和Spring是无缝的。从这个项目的管理和安全上也比Struts2高(当然Struts2也可以通过不同的目录结构和相关配置做到SpringMVC一样的效果,但是需要xml配置的地方不少)。

    9、 设计思想上,Struts2更加符合OOP的编程思想, SpringMVC就比较谨慎,在servlet上扩展。

    10、SpringMVC开发效率和性能高于Struts2。
    11、SpringMVC可以认为已经100%零配置。

    mybatis和ibatis区别

    ibatis本是apache的一个开源项目,2010年这个项目由apache software foundation 迁移到了google code,并且改名为mybatis。

    1、Mybatis实现了接口绑定,使用更加方便。
    在ibatis2.x中我们需要在DAO的实现类中指定具体对应哪个xml映射文件,
    而Mybatis实现了DAO接口与xml映射文件的绑定,自动为我们生成接口的具体实现,使用时不需要通过SqlMapClient去指定namespace 和 sql statement id, 只需要在 sql map config 文件中指定接口的 namespace, 并且sql statement id 和 接口的名字意义对应,然后调用对一个接口即可。
    注意:
    虽然Mybatis支持在接口中直接使用annotation的配置方式来简化配置,
    不过强烈建议仍然使用xml配置的方式。毕竟annotation的配置方式功能有限且代码入侵性太强。使用xml配置方式才能体现出Mybatis的优势所在
    2、对象关系映射的改进,效率更高
    相信很多在使用ibatis2.x的朋友并没有通过ibatis的xml映射文件来实现对象间的关系映射。其实也确实没有必要那么做,因为ibatis2.x采用的是“嵌套查询”的方式将对象之间的关系通过查询语句的直接拼装来实现,其效果和在DAO或Service中自行封装是一样的。
    不过这种方式存在“N+1查询问题”。
    概括地讲,N+1查询问题可以是这样引起的:
    ? 你执行了一个单独的SQL语句来获取结果列表(就是+1)。
    ? 对返回的每条记录,你执行了一个查询语句来为每个加载细节(就是N)。
    这个问题会导致成百上千的SQL语句被执行。这通常不是期望的。

    而在Mybatis中,除了兼容ibatis2.x中的“嵌套查询”方式外,还提供了直接“嵌套结果”的方式,其效果相当于直接通过一句sql将查询出的dto对象自动封装成所需的对象。
    具体实现方法请自行参考Mybatis官方使用手册,不在此累述.

    不过实际上这一改进所带来的好处也是很有限的。因为这一方式在使用分页的时候并不起作用,或者说嵌套对象的结果集是不允许进行分页的。这一点在Mybatis框架中已经做出了明确的限制(org.apache.ibatis.executor.resultset.NestedResultSetHandler里34行),而实际项目中需要分页的情况又特别多……
    仔细一想,一对多映射确实不能通过配置文件来分页,因为这时查询出的记录数并不等于实际返回对象的size,不过一对一映射为什么也不允许就不太明白了。可能是因为一对一是一对多的特例,而在设计框架的时候并没有考虑去处理或是难于处理这一特例吧。
    3、MyBatis采用功能强大的基于OGNL的表达式来消除其他元素。
    熟悉struts2的人应该对OGNL表达式不会感到陌生,
    MyBatis采用OGNL表达式简化了配置文件的复杂性,使用起来更简洁。
    补充:比较遗憾的是,Mybatis的分页继续沿用ibatis2.x的逻辑分页方式,依赖于JDBC的规范。大数据量时会出现性能问题,要想实现物理分页还得自己想办法改了。

    SSM开发过程:

    第一步:先在spring文件夹里新建spring-dao.xml文件,因为spring的配置太多,我们这里分三层,分别是dao service web。

      1. 读入数据库连接相关参数(jdbc.properties
      2. 配置数据连接池
        1. 配置连接属性,可以不读配置项文件直接在这里写死
        2. 配置c3p0,只配了几个常用的
      3. 配置SqlSessionFactory对象(mybatis-config.xml
      4. 扫描dao层接口,动态实现dao接口,也就是说不需要daoImpl,sql和参数都写在xml文件上

    第二步:接下来到service层了。在spring文件夹里新建spring-service.xml文件。

    1. 扫描service包所有注解 @Service
    2. 配置事务管理器,把事务管理交由spring来完成
    3. 配置基于注解的声明式事务,可以直接在方法上@Transaction

    第三步:配置web层,在spring文件夹里新建spring-web.xml文件。

    1. 开启SpringMVC注解模式,可以使用@RequestMapping,@PathVariable,@ResponseBody等
    2. 对静态资源处理,如js,css,jpg等
    3. 配置jsp 显示ViewResolver,例如在controller中某个方法返回一个string类型的”login”,实际上会返回”/WEB-INF/login.jsp”
    4. 扫描web层 @Controller

    第四步:最后就是修改web.xml文件了,它在webappWEB-INF下。

    web.xml

    <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" metadata-complete="true">
        <!-- 如果是用mvn命令生成的xml,需要修改servlet版本为3.1 -->
        <!-- 配置DispatcherServlet -->
        <servlet>
            <servlet-name>seckill-dispatcher</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 配置springMVC需要加载的配置文件
                spring-dao.xml,spring-service.xml,spring-web.xml
                Mybatis - > spring -> springmvc
             -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:spring/spring-*.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>seckill-dispatcher</servlet-name>
            <!-- 默认匹配所有的请求 -->
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    </web-app>
    

    第五步:Java后台逻辑代码。

  • 相关阅读:
    从句分析
    artDialog ( v 6.0.2 ) content 参数引入页面 html 内容
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 13 罗马数字转整数
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 12 整数转罗马数字
    Java实现 LeetCode 11 盛最多水的容器
    Java实现 LeetCode 11 盛最多水的容器
  • 原文地址:https://www.cnblogs.com/my376908915/p/6769956.html
Copyright © 2020-2023  润新知