迷你MVC教程

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

本文节选自《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页面返回给用户
迷你MVC教程_第1张图片
体系结构

开发环境

IDE项目的目录结构

迷你MVC教程_第2张图片
开发环境

部署环境

将Web项目部署到容器中

迷你MVC教程_第3张图片
部署环境

迭代式的开发和测试

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

第一个表单页面的HTML

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


    
        

Beer Selection Page

Select beer characteristics

Color:

部署和测试开始页面

  1. 在开发环境中创建HTML

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

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

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

  1. 在开发环境中创建DD

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




  
      
    Ch3 Beer
      
    com.example.web.BeerSelect
  
    
  
    Ch3 Beer
      
    /SelectBeer.do
  
    
 

由于原书代码是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

迷你MVC教程_第4张图片
启动Tomcat

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

  1. 测试页面

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

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

逻辑名映射到servlet类文件

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

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

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

在用户发送的http post请求中,“/Beer-v1”不是路径的一部分。在form.html中,它只说:

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

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

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

  1. 容器查找为“Ch3 Beer”的标记
  2. 根据标记中的,容器可以知道有哪个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
"); //这个方法来自ServletRequest接口。注意这个参数与HTML