项目源码分析--如此精辟

基于MVC的jpetstore项目分析 jpetstore为博主 大二下 软件开发架构平台技术 的一项实验内容。 下面是基于MVC的jpetstore项目分析:jpetstore: github地址:https://github.com/SwordHarry/Jpetstore 使用环境:IntelliJ IDEA 开发架构:MVC 数据库连接:JDBC 一、准备工作 创建项目,选择为java web项目 输... 阅读详情

本文并非原创,但此文不放在首页给大家看实在对不起大众,签于不标为原创无法在首页与各位分享这篇文章的原因,我将此博客转载至此

在我看来此文博主并不止分析项目,更重要的提供了一种高效研究项目的方法给各位初学者学习。不多说了,下面是原文:

spring jpetstore研究入门-完结篇

上一文安装篇讲述了如何把jpetstore导入netbeans工程,现在所有已经准备就绪,接下来就可以开始进入正题了。

首先,我先大概介绍一下jpetstore的整体架构,spring的这个版本主要使用了struts+spring+ibatis的框架组合,而在MVC层的框架,这个版本又同时提供了两个实现版本,一个是struts,一个是spring 自带的web框架,而数据库持久层使用的是ibatis框架,这个框架是一个SQL映射框架,轻量级而且使用非常容易,基本上会使用JDBC的朋友看一两个小时就会使用了。
下图是该应用的一个简略架构图,没有什么好的工具,就大概画了一个,虽然比较简单,不过也基本可以概括应用的整体框架了,首先是JSP请求,通过struts-config.xml(这里只是根据struts来画的,spring其实也差不多),请求转到相应的Action中,可以看到,这里有一个BaseAction,是所有Action实现的父类,这个类的作用稍后再讲,然后就是每个Action通过PetStoreFacade的对象调用后台DAO对象,从而通过ibatis进行数据的持久操作,这里使用了门面(Facade)模式,隔离了前台与后台耦合度,而PetStoreFacade就是这个门面。结合下图,相信大家对整个jpetstore会有个大概的了解。



好了,大概的结构讲了下,接下来我们就从代码入手,在这里考虑到struts大家比较熟悉,因此,本文是以struts版本来讲,同时声明,本文并不会一段段代码详细讲述,而只是提供一个学习的参考,大概讲解一下流程,让大家不再茫然不知从哪开始,好了,废话也不多说了。

既然是WEB应用,那当然首先从配置文件看起,那就非web.xml莫属了,打开WEB-INF目录下的web.xml,我们挑出目前我们应该关注的配置代码:

Java代码  收藏代码

    <servlet>  
        <servlet-name>petstore</servlet-name>  
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
        <load-on-startup>2</load-on-startup>  
    </servlet>  
      
    <servlet>  
        <servlet-name>action</servlet-name>  
        <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>  
        <load-on-startup>3</load-on-startup>  
    </servlet>  
      
    <servlet-mapping>  
        <servlet-name>petstore</servlet-name>  
        <!--  
        <servlet-name>action</servlet-name>  
        -->  
        <url-pattern>*.do</url-pattern>  
    </servlet-mapping>  



在这里可看到两个servlet设置,以及一个servlet mapping,第一个petstore的servlet是用于spring web框架的,而第二个action的servlet就是用于struts的,而这个版本的mapping默认的是使用spring web,可以看到,<servlet-name>action</servlet-name>这一行是被注释掉了,我们要使用struts的话,那就把这个注释去掉,改为注释掉<servlet-name>petstore</servlet-name>,好了,如此注释以后,整个应用就会以struts的框架运行。(这些配置是什么意思?如果你还搞不懂的话,建议你先去学学基础再来研究应用吧)

接下来我们可以打开strutc-config.xml文件,这里就是struts的默认配置文件,在这里可以看到struts的相关配置信息。

好了,接下来我们就以一个请求来讲述基本的请求流程,以search为例,生成项目,再启动,成功之后进入应用的首页,我们终于可以看到久违的鹦鹉界面了,激动吧,呵呵,在界面的右上角,有一个Search文本框,我们就以这个Search为例子来讲解,输入一个关键字cat,然后点search,结果出来了,这个过程的内部是如何运作的呢?

我们用鼠标右键点击页面,然后选择属性,我们看到显示的地址可能是:
http://localhost:8080/shop/searchProducts.do;jsessionid=E2D01E327B82D068FEE9D073CA33A2A3

这个地址就是我们刚才点击查询时提交的地址了,我们看到searchProducts.do这个字符串,我们之前在web.xml里面的设置大家还记得吗?

Java代码  收藏代码

            <servlet-mapping>  
        <!--  
        <servlet-name>petstore</servlet-name>  
        -->  
        <servlet-name>action</servlet-name>  
        <url-pattern>*.do</url-pattern>  
    </servlet-mapping>  



代表着所有以.do为结尾的请求,都将被名叫action的servlet处理,也就是通过struts-config配置进行处理,那我们就去struts-config.xml里面看看,打开struts-config.xml文件,ctrl+F弹出查询界面,输入searchProducts,我们就可查到

Java代码  收藏代码

    <action path="/shop/searchProducts" type="org.springframework.samples.jpetstore.web.struts.SearchProductsAction" name="emptyForm" scope="session" validate="false">  
    <forward name="success" path="/WEB-INF/jsp/struts/SearchProducts.jsp"/>  
    </action>  



根据以上配置,我们可以得知,刚才我们的提交将会被SearchProductsAction处理,而该action的form是emptyForm,查找emptyForm这个别名,我们可以找到它指向一个BaseActionForm,打开这个form我们可以看到,里面只有两个validate方法和一个addErrorIfStringEmpty方法,没有任何的属性,那就是说search这个提交并没有把我们输入的关键字保存在form里面,打开SearchProductsAction,我们看到execute方法里的第一句就是:

Java代码  收藏代码

    String keyword = request.getParameter("keyword");  



也就是说我们输入的关键字是以参数的形式传入到request里面,参数名字为“keyword”,我们打开IncludeTop.jsp,这个文件在WEB-INF/jsp/struts目录下。

注意了,jsp目录下分别有spring以及struts两个目录,这两个目录就是分别对应两个web框架的,我们使用的是struts所以jsp代码就到struts目录里面,为什么打开IncludeTop.jsp呢,我们可以看到,无论我们进入哪个页面,search那个文本框都存在,也就是说,这个文本框是被当作一个模板插入到所有页面当中去的,我们随便打开一个页面,就可以看到页面开头都是:

Java代码  收藏代码

    <%@ include file="IncludeTop.jsp" %>  



这句就是把IncludeTop.jsp当作页面头部包含进来,所以凡是包含这个头页面的页面,他们的头部都是一样的,这也是我们在开发中常用的一种方式,统一界面的一种方式,我们也可以看到在这些文件尾部也有类似的代码,如:

Java代码  收藏代码

    <%@ include file="IncludeBottom.jsp" %>  



其作用也是一样。打开IncludeTop.jsp后,我们看到其中有一段代码:

Java代码  收藏代码

    <form action="<c:url value="/shop/searchProducts.do"/>" method="post">  
      <input type="hidden" name="search" value="true"/>  
     <input name="keyword" size="14"/> <input border="0" src="../images/search.gif" type="image" name="search"/>  
    </form>  



这段代码就是我们search文本框以及提交链接的代码,在这里就不做详细介绍了。

好了,接下来我们再看看这个action的后续代码:

Java代码  收藏代码

    if (keyword != null) {  
      if (!StringUtils.hasLength(keyword)) {  
        request.setAttribute("message", "Please enter a keyword to search for, then press the search button.");  
        return mapping.findForward("failure");  
        }  
      PagedListHolder productList = new PagedListHolder(getPetStore().searchProductList(keyword.toLowerCase()));  
      productList.setPageSize(4);  
      request.getSession().setAttribute("SearchProductsAction_productList", productList);  
      request.setAttribute("productList", productList);  
      return mapping.findForward("success");  
    }  



这里第一句就是判断keyword是否为空,不为空就执行其中的代码,我们search的时候这个keyword肯定是不为空的,那就是说这段if包含的代码就是我们search的处理代码了,有的人也许会说,如果我不输入关键字而直接点search呢,这keyword不就是为空了吗?我想这个你在此处加个断点,再运行一下就知道了,虽然你没有输入,但是keyword一样不是null,它将是一个空字符串,而不是空对象。我们看到if里面还包含有一个if,这里就是判断keyword是否为空字符串了,StringUtils.hasLength()方式是一个工具类,用来判断keyword是否为空字符串,如果是空字符串就返回false,而这句判断当返回false时,因为前面有个感叹号,所以值为false就执行被if所包含的语句,里面的代码就是保存一个错误信息,然后return mapping.findForward("failure");,这句的意思就不再解释了。

现在假设我们正确输入keyword,那么程序将不会执行if语句中的代码,直接向下执行,我们看到
Java代码  收藏代码

    PagedListHolder productList = new PagedListHolder(getPetStore().searchProductList(keyword.toLowerCase()));  



这句代码,PagedListHolder是spring提供的一个用来保存查询结构类,通常用来进行分页处理,因此我们可以知道

Java代码  收藏代码

    getPetStore().searchProductList(keyword.toLowerCase())  



这一句就是用来查询,并返回查询结果的。getPetStore()这个方法是继承自BaseAction的,它将获得一个PetStoreFacade的实现,我们打开BaseAction的代码,可以看到如下代码

Java代码  收藏代码

    public void setServlet(ActionServlet actionServlet) {  
            super.setServlet(actionServlet);  
            if (actionServlet != null) {  
                ServletContext servletContext = actionServlet.getServletContext();  
            WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);  
            this.petStore = (PetStoreFacade) wac.getBean("petStore");  
            }  
    }  



这句代码里面最重要的一句就是

Java代码  收藏代码

    WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);  



这句代码的作用就是获取一个WebApplicationContext对象wac,在这里我们只需要知道这个对象的作用,而不对其进行深入研究,通过这个对象,我们可以根据spring的配置文件,获得相应的Bean,下面这句就是用来获取相应bean的语句:

Java代码  收藏代码

    this.petStore = (PetStoreFacade) wac.getBean("petStore");  



petStore这个就是bean的id,这个petStore的bean具体是哪个类呢?我们打开applicationContext.xml,可以找到以下配置代码

Java代码  收藏代码

    <bean id="petStore" class="org.springframework.samples.jpetstore.domain.logic.PetStoreImpl">  
        <property name="accountDao" ref="accountDao"/>  
        <property name="categoryDao" ref="categoryDao"/>  
        <property name="productDao" ref="productDao"/>  
        <property name="itemDao" ref="itemDao"/>  
        <property name="orderDao" ref="orderDao"/>  
    </bean>  



从这里可以看到,petStoreFacade的具体类就是PetStoreImpl,而这个类当中,分别通过spring IOC注入了几个DAO的bean,这几个DAO的配置可以在dataAccessContext-local.xml文件里面找到,我们打开PetStoreImpl这个实现类,我们看到类里有一个searchProductList方法,这个方法就是我们在Action当中调用的方法

Java代码  收藏代码

    return this.productDao.searchProductList(keywords);  



从这句代码可以看出,这个方法是通过调用productDao的searchProductList方法来获得结果的,productDao这个DAO从上面的配置文件可以看出,是通过IOC容器进行注入的,我们打开dataAccessContext-local.xml文件,可以看到

Java代码  收藏代码

    <bean id="productDao" class="org.springframework.samples.jpetstore.dao.ibatis.SqlMapProductDao">  
        <property name="sqlMapClient" ref="sqlMapClient"/>  
    </bean>  



这句配置代表了productDao的实现类就是SqlMapProductDao,同时这个类包含有一个sqlMapClient的属性对象,这个对象也是通过ioc注入的,再在这个配置文件里,我们可以找到如下一段代码

Java代码  收藏代码

    <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">  
        <property name="configLocation" value="WEB-INF/sql-map-config.xml"/>  
        <property name="dataSource" ref="dataSource"/>  
    </bean>  



这段代码就是sqlMapClient这个bean的配置,这里的实现是SqlMapClientFactoryBean,它是spring专门为ibatis框架提供的一个支持,通过这个对象就可以很好的集成ibatis框架,具体的介绍可以通过spring官方文档或者是其他一些教程获得,在这里就不多做介绍。

好了,接下来我们知道了,实际查询数据是通过DAO的实现类SqlMapProductDao进行的,而SqlMapProductDao当中就是通过了ibatis进行数据的查询,从而返回结果,这里也就不多做介绍了,大家可以通过ibatis的教程获得ibatis的使用方法,非常的简单,search操作从前台到后台的大概流程就介绍到这里了。

在这个参考文章中,我并没有对具体技术做过多的讲解,那是因为本文只是作为一个研究jpetstore的参考,提供一个可供参考的研究流程,主要是为了那些想开始研究jpetstore但是又不知道从哪开始或者是不知道如何进行研究的新人朋友们而准备的,如果具体的讲解每一部分,那我想将不仅仅是一篇文章就可以完成的事情,因为这里涉及到struts,spring,ibatis等具体的框架技术,每一个框架基本都可以写成一本书,用一篇文章来讲就不太实际了,而且我个人更倾向于遇到不理解的地方的时候,多使用google来搜索,这样能够进一步加深自己对问题的理解。

好了,关于jpetstore源码研究入门的文章就写到这里结束了,由于本人技术和文笔有限,有错漏或者表达不当的地方请不要介意,欢迎各位朋友来指正。 

原文链接:http://calmness.iteye.com/blog/69750


基于Spring Boot的jpetstore项目分析 将原本MVC架构的jpetstore用Spring Boot重构。 github 地址:https://github.com/SwordHarry/mypetstoreSpringBoot 开发环境:IntelliJ IDEA 集成框架:Spring Boot 前端渲染工具:Thymeleaf ORM框架:Mybatis 在此基本要求上实现的额外功能: 1.添加验证码功能:在... 阅读详情

相关推荐

JPetStoreDemo

MyBatis JPetStore JPetStore 6 是一个完整的 Web 应用程序,构建在 MyBatis 3、Spring 3 和 Stripes 之上。 它可以在 MyBatis 项目站点的下载部分下载。 在本节中,我们将遍历此示例以了解它是如何构建的并学习如何运行它。 见: : 使用 Tomcat 7 运行 在 Tomcat 7 下运行 JPetStore 示例(使用 maven)。 克隆这个仓库 打开命令提示符/shell 并更改为克隆目录 发出以下命令以使用 Tomcat 7 运行项目 mvn clean tomcat7:run 在浏览器中运行应用程序 按 Ctrl-C 停止服务器。

从零开始-实现JpetStore网站-1-建立项目框架以及项目介绍

从零开始-实现JpetStore网站-1-建立项目框架以及项目介绍

chenyaqun的博客 797

jpetstore

由sun公司研发的jpetstore web应用系统,是一个卖宠物的网站,有Java语言编写,是一个开源的helloworld似得web应用系统!

Android View的事件分发机制源码分析

View的事件分发机制 最近看到事件分发机制的讨论,可是细节都忘的差不多了,看以前的笔记写的比较简单,就趁这个机会整(shui)理(wen)吧。 事件分发机制的传递规则 时间分发机制的传递规则可以用以下伪代码表示: public boolean dispatchTouchEvent(MotionEvent ev) { boolean result = false;//事件是...

E的博客 250

jpetstore4.0 (spring+struts+ibatis)

用spring改造的jpetstore4.0,适用于jdk7+,tomcat6+。mysql数据库

FastDDS之共享内存

transport层负责为DDS用户数据收发和服务发现提供通信。包含UDP,TCP,SHM。

u010378559的博客 3085

react的useState源码分析

简单说下为什么React选择函数式组件,主要是class组件比较冗余、生命周期函数写法不友好,骚写法多,functional组件更符合React编程思想等等等。更具体的可以拜读dan大神的blog。其中这句十分精辟的道出函数式组件的优势。但是在16.8之前react的函数式组件十分羸弱,基本只能作用于纯展示组件,主要因为缺少state和生命周期。本人曾经在hooks出来前负责过纯函数式的react项目,所有状态处理都必须在reducer中进行,所有副作用都在saga中执行,可以说是十分艰辛的经历了。

weixin_59558923的博客 359

【TestCenter】RFC2544时延测试

本文介绍了使用Spirent TestCenter测试路由器PPPOE时延的RFC2544标准方法。RFC2544定义了三种时延类型:转发时延(LILO)、存储转发时延(LIFO)和直通时延(FIFO)。文章详细说明了测试步骤,包括测试拓扑搭建、PPPOE环境配置、RFC2544测试任务创建等关键环节,并介绍了如何设置时延参数和查看测试报告。测试结果表明,大字节帧的时延高于小字节帧,且负载越高时延越大。该测试方法遵循国际标准,可全面评估网络设备在不同负载下的性能表现。

lai_2020的博客 1400

FFMPEG 源码分析

FFMPEG 源码分析(-) FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库。FFMPEG是在linux下开发的,但也有windows下的编译版本。  ffmpeg项目由以下几部分组成:  ffmpeg 视频文件转换命令行工具,也支持经过实时电视卡抓取和编码成视频文件.  ffserver 基于HTTP(RTSP正在开发中

阿冬专栏 516

AD9361 LVDS数据接口时序解析与FPGA实现

本文详细解析了AD9361 LVDS数据接口的时序特性与FPGA实现方法,重点探讨了DATA_CLK、Rx_FRAME等关键信号的时序关系及数据拼接技巧。通过Verilog代码示例和调试经验分享,帮助开发者解决跨时钟域处理、IQ数据重组等常见问题,提升射频收发系统的稳定性与性能。

weixin_29186249的博客 128

鸿蒙5.0进阶开发:UI开发-不依赖UI组件的全局自定义弹出框 (openCustomDialog)(推荐)

本文介绍通过入参形式为ComponentContent创建自定义弹出框............

AyomQAQ的博客 1850

Vue源码分析

Vue.js 源码学习笔记 最近饶有兴致的又把最新版 Vue.js 的源码学习了一下,觉得真心不错,个人觉得 Vue.js 的代码非常之优雅而且精辟,作者本身可能无 (bu) 意 (xie) 提及这些。那么,就让我来吧:) 程序结构梳理 Vue.js 是一个非常典型的 MVVM 的程序结构,整个程序从最上层大概分为 全局设计:包括全局接口、默认选项等vm 实例设计:

Generon的博客 2511

YOLOv8自动驾驶系统 —— 夜间低光照条件 详细说明和完整代码

本文提出一种针对夜间低光照优化的自动驾驶车道保持系统方案,基于YOLOv8模型改进,包含三大核心技术:1.采用Retinex理论的多尺度低光增强算法,结合自适应伽马校正;2.改进YOLOv8的车道检测模型,通过夜间专用数据集训练,增加抗眩光处理;3.多传感器融合框架,整合可见光与红外图像。系统实现动态逆透视变换和参数调整,在Jetson Orin硬件上达到30ms级实时性能。测试显示在无照明、眩光干扰等极端场景下保持稳定,代码已开源。扩展方向包括V2X协同定位和自适应大灯联动控制。

u010117029的博客 598

由浅入深理解Java线程池及线程池的如何使用(精辟!!)

原文格式清晰,转载自:https://www.cnblogs.com/superfj/p/7544971.html 前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担。线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory。即便没有这样的情况,大量的线程回收也会给GC带来很大的压力。 为了避免...

HD243608836的博客 285

Transformer实战(39)——多模态生成式Transformer

能够理解多种类型输入的模型被称为多模态模型。多模态学习是人工智能 (Artificial Intelligence, AI) 领域的重要研究方向之一,长期受到众多研究人员的关注。本节将介绍使用多模态模型的生成式 AI,包括文本到图像 (text-to-image) 和文本到音乐 (text-to-music) 的生成模型。将介绍 Stable Diffusion 及其工作原理,同时也将介绍 MusicGen 和 AudioGen 模型。

盼小辉丶的博客 2420

【Python_PySide6学习笔记(二十四)】菜单栏QMenuBar类的基本用法

此篇文章中介绍 PySide6 中 QMenuBar 类的基本用法,包括"创建菜单栏"、"创建一级菜单"、"创建二级菜单"等,会持续更新,有需要的读者可以点赞收藏,也欢迎在评论区进行讨论。

禾戊之昂的博客 1623

Tcmalloc源码分析-1

原文: http://blog.youkuaiyun.com/lchjustc/article/details/6867698

penzchan的专栏 890

YOLO26科研优化:多损失函数(EIoU、SIoU等)融合,让边界框回归精度再上台阶

将原有损失函数替换为我们编写的MultiLoss。例如,在bbox_loss。

LXY_LOVE36的博客 171

FFMPEG源码分析

FFMPEG基本概念: ffmpeg是一个开源的编解码框架,它提供了一个音视频录制,解码和编码库。FFMPEG是在linux下开发的,但也有windows下的编译版本。   ffmpeg项目由以下几部分组成:   ffmpeg 视频文件转换命令行工具,也支持经过实时电视卡抓取和编码成视频文件.   ffserver 基于HTTP(RTSP正在开发中)用于实时广播的多媒体服务器.也支持时间平

itiapp的博客 461

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

上一篇: Java论坛汇总
下一篇: 一个JAVA 程序员的告白
coollor
博客等级 码龄15年 48粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值