【斗医】【5】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://qingkechina.blog.51cto.com/5552198/1317441

三、页面跳转封装

【接上】在《

接下来要完成如下功能:

Web容器(Tomcat)接受到HTTP请求后,Web容器把HTTP转换为HttpServletRequest对象,然后根据请求名称匹配规则找到相应的Servlet,调用servlet-class对应类的doGet()或doPost()方法,在该方法中根据请求名称从全局缓存(FrameCache.businessMap)中读取业务对象(FrameBusiness),由FrameBusiness对象跳转到相应的页面。

1、配置名称为action的Servlet。

打开D:\medical\war\WEB-INF\web.xml文件,在里面填充如下内容:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <servlet>

        <servlet-name>action</servlet-name>

        <servlet-class>com.medical.frame.FrameLauncher</servlet-class>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>action</servlet-name>

        <url-pattern>*.act</url-pattern>

    </servlet-mapping>

    <welcome-file-list>

         <welcome-file>index.html</welcome-file>

    </welcome-file-list>

</web-app>



【备注】:该内容在前面已配置过,这里再强调一次一方面是理顺思路,另一方面是强调Web容器处理HTTP请求的流程。


2、把HttpServletRequest请求均交给get处理

打开D:\medical\src\com\medical\frame\FrameLauncher.java,把doPost()处理交给doGet():


1

2

3

4

5

@Override

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException

{

    doGet(request, response);

}

3、为了保持FrameLauncher功能的简洁性,这里定义一个FrameDispatcher类,FrameLauncher.doGet()的业务逻辑交给FrameDispatcher处理:

I、定义com.medical.frame.FrameDispatcher.java类


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class FrameDispatcher

{

    private HttpServlet servlet = null;

    /**

     * 构造器

     */

    public FrameDispatcher(HttpServlet servlet)

    {

        this.servlet = servlet;

    }

    public void process(HttpServletRequest request, HttpServletResponse response) throws FrameException

    {

        // TODO

    }

}

II、FrameLauncher.doGet()交给FrameDispatcher对象处理


1

2

3

4

5

6

7

8

9

10

11

12

13

@Override

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException

{

    FrameDispatcher dispatcher = new FrameDispatcher(this);

    try

    {

        dispatcher.process(request, response);

    }

    catch (FrameException e)

    {

        logger.error(e.getErrorDesc(), e);

    }

}

4、定义FrameDispatcher.getRequestName(HttpServletRequest)方法从HttpServletRequest对象中解析出请求名称(比如从/medical/index.act中获取index)


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

/**

 * 由HttpServletRequest对象获取请求名称

 */

private String getRequestName(HttpServletRequest request)

{

    String name = request.getRequestURI();

    if (name == null)

    {

        return null;

    }

    if (name.endsWith(FrameConstant.BUS_NAME_POSTFIX) == false)

    {

        return null;

    }

    int headIndex = name.lastIndexOf("/") + 1;

    int rearIndex = name.lastIndexOf(FrameConstant.BUS_NAME_POSTFIX);

    return name.substring(headIndex, rearIndex);

}

5、修改FrameDispatcher.process()方法,其功能是由业务名称获取对应的业务对象,然后由业务对象的forward来决定跳转页面

6、下面初步测试一下:

I、修改D:\medical\war\index.html文件,该文件加载完就跳转到index.act


1

2

3

4

5

6

7

8

9

<!DOCTYPE HTML>

<html>

    <head>

        <title>medical</title>

        <script type="text/javascript">

            top.location="index.act";

        </script>

    </head>  

</html>

II、修改D:\medical\war\WEB-INF\config\sm\system-action.xml文件


1

2

3

4

5

6

<business name="index" mustlogin="false">

    <forward>

        <path name="success"  path="/module/main/main.html"/> 

        <path name="failure"  path="/module/main/main.html"/>

    </forward>

</business>

当系统加载时名称为action的Servlet会把该文件读入全局缓存。访问index.html时执行top.location="index.act",action接受到"*.act"就执行FrameDispatcher.process()方法,从而跳转到/module/main/main.html页面

III、在D:\medical\war\module\main\下创建main.html文件,这里只是为了测试,所以main.html只是输出一个<h1>This is main page!</h1>标题:


1

2

3

4

5

6

7

8

9

<!DOCTYPE HTML>

<html>

    <head>

        <title>medical</title>      

    </head>

    <body>

        <h1>This is main page!</h1>

    </body>

</html>

IV、启动Tomcat服务,在浏览器中输入http://localhost:8080/medical,会发现页面直接把<h1>This is main page!</h1>显示出来了,见下图:


【备注】:细心的读者可能发现了页面进入了main.html,但地址却依旧停留在index.act处,见上图。其中原因请大家在谷歌上搜索一下“JSP forward”,有文章会给出详细说明。


7、再仔细考虑一个场景:在跳转到页面A之前,(1)有可能需要把当前页面的数据保存在数据库中,(2)或者需要进行一些逻辑判断,符合条件才能进入A页面,不符合则不能进入A页面。这就是当时XXX-action.xml中业务定义"business-class"的原因,但我们的FrameDispatcher.process()并没有这方面的处理,现在进行修改:

I、定义缺省跳转动作执行类com.medical.frame.FrameDefaultAction.java


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

/**

 * 斗医系统业务缺省跳转处理器

 *

 * @author qingkechina

 */

public class FrameDefaultAction

{

    /**

     * 请求对象

     */

    protected HttpServletRequest request = null;

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    /**

     * 响应对象

     */

    protected HttpServletResponse response = null;

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    /**

     * 会话对象

     */

    protected HttpSession session = null;

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    public void setRequest(HttpServletRequest request)

    {

        this.request = request;

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    public void setResponse(HttpServletResponse response)

    {

        this.response = response;

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    public void setSession(HttpSession session)

    {

        this.session = session;

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    /**

     * 读取Request对象中的参数

     */

    public String getParameter(String param)

    {

        return request.getParameter(param);

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      

    /**

     * 缺省响应动作

     */

    public String execute() throws FrameException

    {

        return null;

    }

}



【备注】:这里没有使用接口或抽象类,建议读者在自已实现该功能时最好能抽象出接口,这样做的好处可参见设计模式相关内容


II、定义动作工厂,可以根据XXX-action.xml中的业务business-class名称把相关的跳转动作类反射出来


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

package com.medical.frame;

import com.medical.frame.constant.FrameConstant;

import com.medical.frame.constant.FrameErrorCode;

/**

 * 斗医系统业务跳转动作工厂类

 *

 * @author qingkechina

 */

public class FrameActionFactory

{

    private static FrameActionFactory instance = new FrameActionFactory();

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

    private FrameActionFactory()

    {

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

    public static FrameActionFactory getInstance()

    {

        return instance;

    }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           

    /**

     * 反射跳转动作实现类

     */

    public FrameDefaultAction implement(String className) throws FrameException

    {

        if (className == null || className.trim().length() == 0)

        {

            className = FrameConstant.FORWARD_DEFAULT_ACTION;

        }

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

        try

        {

            return (FrameDefaultAction) Class.forName(className).newInstance();

        }

        catch (Exception e)

        {

            throw new FrameException(FrameErrorCode.JAVA_REFLECT_ERROR, e);

        }

    }

}

III、修改FrameDispatcher.process()方法,在其中增加跳转动作逻辑部分的处理(即下图红框部分):

8、测试跳转功能:

I、打开D:\medical\war\WEB-INF\config\sm\system-action.xml文件,对"index.act"动作指定逻辑响应处理类Demo


1

2

3

4

5

6

<business name="index" mustlogin="false" business-class="com.medical.frame.forward.Demo">

    <forward>

        <path name="success"  path="/module/main/main.html"/>

        <path name="failure"  path="/module/main/main.html"/>

    </forward>

</business>

II、定义com.medical.frame.forward.Demo类,该类继承FrameDefaultAction类,并重写execute()方法


1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.medical.frame.forward;

import com.medical.frame.FrameDefaultAction;

import com.medical.frame.FrameException;

public class Demo extends FrameDefaultAction

{

    @Override

    public String execute() throws FrameException

    {

        // 这里可以处理一些逻辑

        System.out.println("===================这里可以进行逻辑处理");

        // 逻辑处理完后跳转到相应页面

        return "login.act";

    }

}

从代码上可以看出,这里逻辑处理完之后,就直接跳转到login.act对应的页面

III、打开D:\medical\war\WEB-INF\config\sm\system-action.xml文件,修改"login.act"对应的业务配置


1

2

3

4

5

6

<business name="login" mustlogin="">

    <forward>

        <path name="success"  path="/module/login/login.html"/>

        <path name="failure"  path="/module/login/login.html"/>

    </forward>

</business>

IV、在D:\medical\war\module\login下创建login.html文件,填充如下内容:


1

2

3

4

5

6

7

8

9

<!DOCTYPE HTML>

<html>

    <head>

        <title>medical</title>

    </head>

    <body>

        <h1>This is Login page!</h1>

    </body>

</html>

V、启动Tomcat后在浏览器中输入http://localhost:8080/medical回车,查看页面,页面上输出“This is Login page!”,这说明页面是跳转到了login.html上,如图:



【备注】:上面的测试也说明当业务配置了business-class,则相应动作执行类跳转动作的优先级要高于<forward>


OK,到这里跳转封装的基本功能已完成,可能会有人问:“只是一个跳转,使用HTML的<a>标签,岂不是更简单,何苦折腾这么一通呢?”

有这个疑问是一件好事情,说明大家都进行了思考。正如上面所说,一些逻辑性处理需要在服务端进行(如有些场景需要根据逻辑判断决定跳转到哪个页面,若纯使用WEB前端处理,显的客户端比较胖或者叫富客户端),另外把眼光放远一些,试想Struts做了哪些事情呢?除了过滤器之外无非也是逻辑判断,数据加工后的页面显示。

下面我们再理顺一下思路:

(1)启动Tomcat时,会加载web.xml,根据web.xml把名称为action的Servlet拉起

(2)名称为action的Servlet启动时,根据其配置规则反射FrameLauncher类,并调用它的init()方法

(3)在init()方法中会读取运行环境中的XXX-action.xml文件,解析该文件后把动作名及动作名对应的业务对象FrameBusiness缓存入全局变量

(4)当在浏览器中输入http://localhost:8080/medical时,Tomcat根据web.xml配置首先加载index.html

(5)在index.html加载完毕后直接使用top.location="index.act"跳转到index.act

(6)tomcat服务器一看到是.act结尾的请求,就使用FrameLauncher的doGet()方法来处理

(7)FrameLauncher.doGet()委托给FrameDispatcher.process(),在process()中它根据index.act在全局缓存中查找FrameBusiness

(8)首先看一下FrameBusiness是否有class-name,若有就获取逻辑处理类指定的路径;若没有就使用forward指定的路径

(9)然后把该路径交给HttpServlet进行具体的页面跳转

本文出自 “青客” 博客,请务必保留此出处http://qingkechina.blog.51cto.com/5552198/1317441

时间: 2024-12-27 11:37:06

【斗医】【5】Web应用开发20天的相关文章

【斗医】【17】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1543919     细心的读者可能已发现"Web应用开发50天"改为了"Web应用开发20天",之所以这样调整是因为当时想前20篇只讲解Web基础知识,中间10篇讲解我一直想要封装的Web框架,后20篇将该应用转换为Android应用.但由于最近女儿出生,业余时间都被她占用了,

【斗医】【7】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1330647 现在想想一下首页放置哪些内容?由于该WEB应用的聚集点在"斗"上,也就是对医术的探讨方面,个人认为应该是对展示较新的或评价较好的病症药方的展示方面.这里包含两部分:(1)数据的获取,即动态读取较好或评价较好的药方数据:(2)页面的展示,即静态页面布局和数据显示. 对于第一个问题会涉及到

【斗医】【9】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1377044 一.调试<[斗医][8]Web应用开发50天>数据表映射方法    本来想把数据库配置.Hibernate连接封装和映射配置一块写的,但由于个人时间问题时断时续,思路也多次被打断,所以在此对其进行弥补.    若读者把上篇的附件下载下来运行,会发现运行失败,下面随着异常分析并解决. 1.截止目

【斗医】【11】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1386941 本文在上文的基础上完成用户登录验证功能. 四.获取数据请求业务处理封装 1.配置数据读取方式,它的作用是使用FrameDataGainer响应以.data结尾的请求,并把处理后的数据返回给客户端.打开D:\medical\war\WEB-INF\web.xml文件,填充如下内容: 1 2 3 4

【斗医】【12】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1390410 在上文中有意埋了几个安全彩蛋,以便后面在聊网络安全时使用. 书接前言,对上文做过实践的朋友肯定会发现:当用户注册/登录成功后页面跳转到了系统首页,但首页的导航菜单并没有显示用户名.本文重点实现这个特性,同时也谈谈系统的编码问题. 六.注册/登录成功后导航菜单显示当前用户名    与JSP不同之处

【斗医】【6】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1322419 对于一个网站来讲均会存在公共页面,如异常页面.系统菜单等等,本章针对斗医系统菜单做一下介绍.可以想一想常见网站的系统菜单形式,一般都是菜单项在每个页面的内容不变,区别是菜单的选择状态不同. JSP可以使用<%@ include file="">语句把公共系统菜单页面引进来,

【斗医】【4】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1315778 在上面把日志文件打印到了D:\log下,考虑到Liunx服务器环境下,让最终用户修改可能不可接受,接下来完成三件事情:(1)应用程序指定输出路径(2)完善异常类的处理(3)完成页面跳转的封装处理 一.指定输出路径 由于Logback的<FILE>指定相对路径与Log4J存在差异,所以在修改日志

【斗医】【3】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1308932 在上面提及异常的中英文从资源文件中读取,若读取失败需要日志记录,所以使用网上正在闹腾的Logback来记录.关于Logback与Log4j这里不做评判和说明,所有疑问可以请教谷歌. 一.Logback的使用前期准备 1.在官网http://logback.qos.ch/download.html

【斗医】【1】Web应用开发20天

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://qingkechina.blog.51cto.com/5552198/1303925 从哪里开始呢? 还是从前段认识的朋友开始吧. 前段在圈里认识了一个朋友,当他聊到他用SSH开发了一套系统时,我思想意识中想到SSH应该是一个通讯协议,他用不可置否的语气说:大叔,你从事这一行业也这么多年了,难道不知道SSH? 说来惭愧,从事这行业时间真的不短了,好像没有真的从事过WEB方面的开发