迷你MVC教程——命令行方式创建第一个servelt小程序

迷你MVC教程

本文节选自《Head First Servlets and JSP》第3章 MVC实战,根据个人配置和实操情况有所删改。本人注解部分用斜体表示。图片截取自原书,部分为个人操作截图。本人电脑配置win10x64, tomcat7, jdk10。本教程的特色处在于全程采用手工编写和命令行结合,不借助IDE开发环境,适合初次接触Servlet者当作练习的小项目。任何问题请在下方留言。

构建小型Web应用步骤

  1. 分析用户的视图以及高层体系结构
  2. 创建用于开发这个项目的开发环境
  3. 创建用于部署这个项目的部署环境
  4. 对Web应用的各个组件完成迭代式的开发和测试

(基于Beer Advisor的案例。根据用户选择的酒色提供酒的品牌建议的servlet小程序

用户视图

  • 用户最初请求的HTML表单,生成HTTP POST请求
  • 处理请求返回的result.jsp

体系结构

  1. 客户请求得到form.html页面
  2. 容器获得form.html页面
  3. 容器把这个页面返回给浏览器,用户再在浏览器上回答表单上的问题
  4. 浏览器把请求数据发送给容器
  5. 容器根据URL查找正确的servlet,并把请求传递给这个servlet
  6. servlet调用BeerExpert寻求帮助
  7. BeerExpert类返回一个回答,servlet把这个回答增加到请求对象
  8. servlet把请求转发给JSP
  9. JSP从请求对象得到回答
  10. JSP为容器生成一个页面
  11. 容器将jsp页面返回给用户

体系结构

开发环境

IDE项目的目录结构

开发环境

部署环境

将Web项目部署到容器中

部署环境

迭代式的开发和测试

  1. 构建和测试用户最初请求的HTML表单
  2. 构建控制器servlet的第一个版本,并用HTML表单测试这个控制器。这个版本通过HTML表单来调用,并打印出它接收到的参数
  3. 为模型类构建一个测试类,然后构建并测试模型类本身
  4. 把servlet升级到第2版。这个版本增加了一个功能,可以调用模型类来得到啤酒建议。
  5. 构建JSP, 把servlet升级到第3版本(增加一个功能,可以把表示流分派到JSP完成),然后再测试整个应用。
第一个表单页面的HTML

form.html包含标题文本,一个下拉列表,还有一个提交按钮(原书代码)

<html>
    <body>
        <h1 align="center">
            Beer Selection Page
        </h1>
        <!--为什么选择POST而不是GET? HTML认为这就是要调用servlet。在你的目录结构里没有一个叫“SelectBeer.do”的东西。这只是一个逻辑名-->
        <form method="POST" action="SelectBeer.do">
            <p>
                Select beer characteristics
            </p>
            Color:
            <select name="color" size="1">
                <!--我们就是这样拆个那就下拉菜单的,你可以有自己不同的选项-->
                <option value="light">light</option>
                <option value="amber">amber</option>
                <option value="brown">brown</option>
                <option value="dark">dark</option>
            </select>
            <br><br>
            <center>
            <input type="SUBMIT">
            </center>
        </form>
    </body>
</html>
部署和测试开始页面
  1. 在开发环境中创建HTML

创建这个HTML文件,取名为form.html,然后保存在开发环境的/beerV1/web/目录下

  1. 把这个文件复制到部署环境

把form.html文件的一个副本放在tomcat/webapps/Beer-vl/中

  1. 在开发环境中创建DD

创建XML文档,取名为web.xml, 把它保存在开发环境的/beer/etc/目录下(原书代码)

<!--没有必要知道这是什么意思,只需要照着输入就行-->
<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" id="WebApp_ID" version="3.0">

  <servlet>
      <!--这是一个虚构的名字,只能在DD的其他部分使用-->
    <servlet-name>Ch3 Beer</servlet-name>
      <!--servlet类文件的完全限定名-->
    <servlet-class>com.example.web.BeerSelect</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>Ch3 Beer</servlet-name>
      <!--不要忘记最前面有一个斜线。我们希望用户这样引用“servlet.do”只是一个约定-->
    <url-pattern>/SelectBeer.do</url-pattern>
  </servlet-mapping>

</web-app> 

由于原书代码是tomcat5, 版本有所变化,可以到tomcat/webapps/ROOT/WEB-INF自带目录下拷贝了一份web-xml文件,并添加相应的映射语句。

  1. 把这个文件复制到部署环境

把web.xml文件的一个副本放在tomcat/webapps/Beer-v1/WEB-INF/

  1. 启动Tomcat

Tomcat既作为Web服务器,又作为Web容器。要启动Tomcat, 先用cd命令切换到tomcat主目录,再运行bin/startup.sh

启动Tomcat

命令行中用cd切换到tomcat/bin目录下(tomcat根据版本名称不同),win系统运行startup.bat

  1. 测试页面

在浏览器中打开这个HTML页面,为此键入:

http://localhost:8080/Beer-v1/form.html

逻辑名映射到servlet类文件

以下部分为xml文件中配置的详解

  1. 用户填写表单,然后点击submit。浏览器生成了以下请求URL:

/1Beer-v1[^2]/SelectBeer.do[^3]

在用户发送的http post请求中,“/Beer-v1”不是路径的一部分。在form.html中,它只说:<form method="POST" action="SelectBeer.do>"

但浏览器为请求追加了“/Beer-v1/”,因为用户请求就来自这里。换句话说,form.html中的“SelectBeer.do”相对于其所在页面的URL。在这里,就是相对于Web应用的根:“/Beer-v1”

  1. 容器搜索DD, 找到<url-pattern>与/SelectBeer.do匹配的一个<servlet-mapping>, 这里的斜线{/}表示Web应用的上下文根,SelectBeer.do就是资源的逻辑名
  2. 容器看到对应这个<url-pattern><servlet-name>是“Ch3 Beer”。但是这并不是实际servlet类文件的名字。“Ch3 Beer”是servlet名,而不是servlet类的名字。

对容器来说,servlet只是在DD中<servlet>标记下的一个东西。servlet名只在DD中使用,以便DD的其他部分建立与该servlet的映射

  1. 容器查找<servlet-name>为“Ch3 Beer”的<servlet>标记
  2. 根据<servlet>标记中的<servlet-class>,容器可以知道有哪个servlet类负责处理这个请求。如果这个servlet还没有初始化,就会加载类,并初始化servlet
  3. 容器开始一个新线程来处理这个请求,并把请求传递给这个线程(传递给servelt的service()方法)
  4. 容器把响应(通过Web服务器)发回给用户
控制器servlet的第1版

确保HTML页面能适当地调用servlet, 而且servlet能正确地接收HTML参数。

(原书代码)

//确保与前面创建的开发结构和部署结构匹配
package com.example.web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

//HttpServlet扩展了GenericServlet,GenericServlet则实现了Servlet接口
public class BeerSelect extends HttpServlet{

    //我们使用doPOST来处理HTTP请求,因为HTML表单指出,method=POST
    public void doPost(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{

        //这个方法来自ServletResponse接口
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("Beer Selection Advice<br>");
        //这个方法来自ServletRequest接口。注意这个参数与HTML<select>标记中"name"属性的值匹配
        String c = request.getParameter("color");
        //这里我们没有返回建议,只是把测试信息显示出来
        out.println("<br>Got beer color "+c);
    }
}
编译、部署和测试控制器servlet

编译servlet

用-d标志编译servlet,把类放在开发环境中

原书

编译servlet

win系统

win系统编译servelt

注解:-classpath用于设置临时环境变量,指定查找用户类文件和注释处理程序的位置;本例中由于编译servlet需要用到额外类库,tomcat提供了这些jar包,故选定tomcat/lib/servlet-api.jar为环境变量。书中还添加了classes和”.”(代表当前目录)作为路径,其实可以略去。

-d用于指定编译生成的class文件存放目录,本例中存放于classes路径中,由于servlet的package语句,会自动生成com.example.web目录(若不存在)。

最后,添上servlet类的存放路径,若存放在当前目录则直接输入文件名。

部署servlet

要部署servlet, 建立.class文件的一个副本,并把它移到部署结构的/Beer-v1/WEB-INF/classes/com/example/web/目录下

测试

  1. 重启tomcat

重启tomcat

直接在tomcat/bin目录下输入startup.bat命令即可重启,无须关闭

  1. 启动浏览器,访问:

http://localhost:8080/Beer-v1/form.html

  1. 选择一种啤酒颜色,点击“Submit”
  2. 如果你的servlet能正常运行,就能在浏览器上看到servlet的响应显示为:

Beer Selection Advice

Got beer color brown

构建和测试模型类

模型规范

  • 包应当是com.example.model
  • 其目录结构应当是/WEB-INF/classes/com/model
  • 提供一个方法getBrands(), 取一个喜欢的啤酒颜色(String)作为参数,并返回一个ArrayList, 其中包含推荐的啤酒品牌(String)

为模型构建测试类

为模型创建测试类(在构建模型本身之前先创建测试类)。刚开始测试模型时,模型还在开发环境中,与其他Java类一样,此时无需启动Tomcat也能测试

作者代码(我是在创建模型类后再创建测试类)

package com.example.model;

import java.util.*;

class BeerExpertTest{
    public static void main(String[] args){
    BeerExpert be=new BeerExpert();
    List<String> testBrands1=be.getBrands("amber");
    Iterator it1=testBrands1.iterator();
    while(it1.hasNext()){
    System.out.println("try1: "+it1.next());
        }
    System.out.println("----------------------");
    List<String> testBrands2=be.getBrands("");
    Iterator it2=testBrands2.iterator();
    while(it2.hasNext()){
    System.out.println("try2: "+it2.next());
        }
    }
}

命令行中运行测试类(请在构建模型类后进行此步)

编译测试类

运行此步后,开发环境项目中的/classes/com/example/model中会生成两个.class文件(原来BeerExpert编译的.class文件被更新)。-classpath中的./src为测试类所依赖的模型类(com.example.model.BeerExpert)的查找路径。原教材中无此步,可略过。

可以切换至测试类所在包的基目录,然后运行java命令
解析运行测试类方法1

也可以直接在beerV1/下设置环境变量为classes目录
解析运行测设类方法2

构建和测试模型

(原书代码,增加了List泛型为String类)

package com.example.model;
import java.util.*;

public class BeerExpert{
    public List<String> getBrands(String color){
        List<String> brands = new ArrayList()<String>;
        if (color.equals("amber")){
            brands.add("Jack Amber");
            brands.add("Red Moose");
        }else{
            brands.add("Jail Pale Ale");
            brands.add("Gout Stout");
        }
        return(brands);
    }
} 

编译模型类

win系统与上图操作命令一致,因为模型类中没有导入其他外部类,所以无须设置classpath变量

改进servlet,调用模型得到真正的建议

第2版的servlet中,通过改进doPost()方法,调用模型来得到建议(第3版还会向JSP提供建议)

改进servlet, 第2版

先把servlet放在一边,只考虑Java

  1. 改进doPost()方法来调用模型
  2. 编译servlet
  3. 部署和测试更新后的Web应用

(作者代码,增加了List泛型部分,作者改用增强for循环遍历集合,也可采用原书中的iterator迭代器遍历)

import com.example.model;
public class BeerSelect2 extends HttpServlet{
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("Beer selection Advice<br>");
        String c = request.getParameter("color");
        BeerExpert be = new BeerExpert();
        List<String> advisedBrands= be.getBrands(c);
        for(String ad:advisedBrands){
            out.print("<br>try:"+ad);
        }
    }
}

注:原书中每次修改都替换原始的servlet, 作者采用创建新的servlet方式,以便区分不同版本的servlet——此方式需要在xml配置文件中相应修改servlet类完全限定名

第2版Servlet代码
package com.example.web;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import com.example.model.*;
import java.util.*;

public class BeerSelect2 extends HttpServlet{

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

        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("Beer selection Advice<br>");
        String c = request.getParameter("color");
        BeerExpert be = new BeerExpert();
        List<String> advisedBrands= be.getBrands(c);
        for(String ad:advisedBrands){
            out.print("<br>try:"+ad);

    }
}
}
第2版servlet的关键步骤

主要有两件事要做:重新编译servlet和部署模型类

编译servlet

编译servlet

win系统下

win系统编译servlet

注:第2版servlet与前一版不同之处在于调用了模型,故在classpath环境变量中添加模型类的路径

部署和测试Web应用

  1. 把servlet.class文件的一个副本移到以下位置:

../Beer-v1/WEB-INF/classes/com/example/web/

这会替换第1版的servlet类文件

  1. 把模型的.class文件副本移到:

../Beer-v1/WEB-INF/classes/com/example/model/

  1. 关闭并重启tomcat
  2. 通过form.html**测试这个应用**
创建提供建议的JSP”视图”
<!--这是一个“页面指令”-->
<%@ page import="java.util.*" %>

<html>
    <body>
        <!--一些标准HTML模板-->
        <h1 align="center">
            Beer Recommendations JSP
        </h1>
        <br>
        <!--以下称为scriptlet代码,用于输入java代码-->
        <%
        //这里从请求对象得到一个属性
        List styles=(List)request.getAttribute("styles");
        Iterator it = styles.iterator();
        while(it.hasNext()){
            out.print("<br>try:"+it.next());
        }
        %>
    </body>
</html>

部署JSP

不用编译JSP(这个工作会在第一个请求到达容器时由容器完成)

  1. 把它命名为“result.jsp”
  2. 保存再开发环境的/web/中
  3. 将其副本移到部署环境的/Beer-v1/中
改进这个servlet,让它”调用“JSP(第3版)

这一步,我们要把servlet修改为”调用“JSP来生成输出(视图)。容器提供了一种称为”请求分派“的机制,允许容器管理一个组件调用另一个组件。我们通过使用这种机制,servlet从模型中得到信息,把它保存在请求对象中,然后把请求分派给JSP

必须对这个servlet做的重要修改

  1. 把模型组件的回答增加到请求对象,以便JSP访问
  2. 要求容器把请求转发给”result.jsp”
第3版servlet的代码

如下修改servlet, 将模型组件的回答增加到请求对象(以便JSP获取),并要求容器把请求分派给JSP

(作者代码,修改了类名和泛型,需要在xml文件修改配置)

package com.example.web;

import com.example.model.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;

public class BeerSelect3 extends HttpServlet{
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{
        String c = request.getParameter("color");
        BeerExpert be = new BeerExpert();
        List<String> result = be.getBrands(c);

       //为请求对象增加一个属性,供JSP使用。注意,JSP要寻找"styles"
        request.setAttribute("styles", result);
        //为JSP实例化一个请求分派器
        RequestDispatcher view = request.getRequestDispatcher("result.jsp");
        //使用请求分派器要求容器准备好JSP,并向JSP发送请求和响应
        view.forward(request,response);
    }
}
编译、部署和测试最后的应用

编译servlet

部署和测试Web应用

  1. 把servlet的.class文件副本移到../Beer-v1/WEB-INF/classes/com/example/web/
  2. 关闭并重启tomcat
  3. 通过form.html测试应用

  1. 主机服务器的根
    [^2]: Web应用上下文
    [^3]: 逻辑资源名
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值