小白新手web开发简单总结(三)-一个简单的Web开发项目

目录

一 前言

二 web应用开发

1.什么是web应用开发

2.一个简单的web应用

3.实际的web应用

三 web应用开发的断点调试

四 总结


一 前言

经过小白新手web开发简单总结(一)-什么是Tomcat小白新手web开发简单总结(二)-什么是web.xml,对一个web开发有了一点点认识,一个开发的流程应该大概是这个样子:

  • 1.一个web项目开发最后通过maven把项目代码(前端页面展示+业务逻辑)打包成war包;
  • 2.在服务器上安装Tomcat,那么在安装目录下就会有一个webapps的文件夹,那么我们就把第一步打包成的war包放到该目录下。(从webapps这个命名方式上也可以看出,该Tomcat是可以启动多个web应用);
  • 3.进入到bin的目录下,运行.startup.sh,启动Tomcat,那么就会读取war包里面的web.xml配置文件,按照小白新手web开发简单总结(二)-什么是web.xml实例化里面的类,那么我们就可以通过在浏览器中输入url来访问web应用了。

上面的三点总结是基于我在本地电脑上的一个操作方式总结出来的,真正的在一个网站开发过程中的操作过程,后面再去研究,但我觉得应该差不多也是这个样子。所以对于后面在学习一个web开发,我觉得需要学习下到底Spring、Spring MVC、Tomcat之间的关系,一个请求过来,到底是怎么完成一次请求的?

二 web应用开发

1.什么是web应用开发

web应用开发一般都会采用B/S架构。从开发角度来分,我觉得一个web应用开发和一个APP的开发一样,可以划分为包括的分成这几部分:web页面相关的业务逻辑+网络通信+网络提供给业务层调用的功能。 对于用户来说,只需要浏览器,web应用的相关业务逻辑和数据都存在在服务端。浏览器通过Http协议与服务器进行通信,获取web页面的内容,通过浏览器显示给用户。

浏览器在整个过程中的角色:

(1)与服务器建立TCP连接;

(2)发送Http请求,在该请求中会标明GET/POST;

(3)接收Http响应,将服务器返回的内容显示在浏览器中。

在请求和响应都包括Http Header和Http Body,响应体根据设置的Content-Type返回对应的网页数据(如text/html,则会返回<html></html>),浏览器将这些信息显示出来即可。浏览器获取的第一个资源就是这些Html网页,如果里面还含有JavaScript、CSS、图片等资源,浏览器会根据对应的资源url再一次向服务器发送请求。

服务器在整个过程中的角色:

(1)与浏览器建立TCP连接;

(2)识别Http请求,接收和处理Http请求;

(3)将处理之后的Http请求返回给浏览器。

从角色分工中,可以看出,服务器已经处理和解析Http请求等网络通信的工作,浏览器负责发送和接收Http请求,而web应用只需要放到web服务器即可。在Java EE提供HttpServlet来处理Http请求,那么只要该服务器去实现HttpServlet,就可以实现网络通信的工作。

2.一个简单的web应用

我觉得可以把HttpSerlvet理解成一个处理客户端发过来的Http请求的类,里面有两个方法:

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
protected void doPost(HttpServletRequest req, HttpServletResponse resp)

其中参数HttpServletRequest req, HttpServletResponse resp就代表这请求和响应。在使用这个HttpSerlvet的时候,不需要关心怎么与TCP交互,也不需要解析Http,例如在doGet()方法只需要:从req中接收到浏览器发过来的请求参数,在该方法中完成业务逻辑和读写数据库的操作,最后将结果写入到resp,那么浏览器就可以接收到相关的数据,在res和resp中已经封装了请求和响应的逻辑。

通过这个HttpSerlvet来完成一个简单的web应用开发的实例:

(1)通过IDEA创建一个Maven工程

(2)配置pom.xml,引入Servlet

    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

这里注意要将该依赖作为<provided>(即设置  <scope>provided</scope>)引入,这样仅会在编译的时候使用,最后不会打包到.war包中,因为在后面用到的Tomcat服务器中已经有相应的Servlet API。 

 (3)配置打包类型为.war,同时配置最后打包成.war的名字

    <packaging>war</packaging>
    <build>
        <finalName>builder-spring</finalName>
    </build>

(4)在java的目录下创建一个FirstServlet的java文件,并且编写一个简单的显示一句话。

@WebServlet(urlPatterns = "/")
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.write("<h1> Hello Web ,This is a simple web!</h1>");
        //强制输出
        writer.flush();
    }
}

当然也可以通过getOutputStream()获取写入流 。另外需要注意的是在写入完毕之后,必须调用flush(),否则不能将这些数据及时返回给浏览器,而close(),是关闭的TCP连接,不能调用该方法。

(5)在项目工程的main/webapp/WEB-INF的目录下,创建web应用的描述文件web.xml

<!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>
    <display-name>build spring</display-name>
</web-app>

(6)通过IDEA自带的maven进行打包,依次执行clean->compile->package,然后在target的目录下就会生成build-spring.war包

(7)将build-spring.war包拷贝到在Tomcat的安装目录webapps,在返回到bin目录下,运行.startup.sh,在终端命令窗口显示:

MacBook-Pro:bin j1$ ./startup.sh 
Using CATALINA_BASE:   /Users/j1/Documents/java/apache-tomcat-9.0.41
Using CATALINA_HOME:   /Users/j1/Documents/java/apache-tomcat-9.0.41
Using CATALINA_TMPDIR: /Users/j1/Documents/java/apache-tomcat-9.0.41/temp
Using JRE_HOME:        /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
Using CLASSPATH:       /Users/j1/Documents/java/apache-tomcat-9.0.41/bin/bootstrap.jar:/Users/j1/Documents/java/apache-tomcat-9.0.41/bin/tomcat-juli.jar
Using CATALINA_OPTS:   
Tomcat started.

(8)在浏览器中输入http://localhost:8080/builder-spring/,其中这个/builder-spring/就是war包的名字,就可以看到如下界面

当然也可以通过http://localhost:8080/builder-spring/?count=2 来添加参数,那么在FirstServlet可以直接通过HttpServletRequest读取:

@WebServlet(urlPatterns = "/")
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        String count = req.getParameter("count");
        PrintWriter writer = resp.getWriter();
        writer.write(String.format("<h1> Hello Web %s ,This is a simple web!</h1>",count));
        //强制输出
        writer.flush();
    }

在浏览器中访问如下: 

通过上面的几个步骤,成功的创建了一个简单的web应用。当浏览器在访问"http://localhost:8080/builder-spring/"的时候,就会发送请求, 然后有Tomcat(前面的小白新手web开发简单总结(一)-什么是Tomcat也提到了Tomcat其实就是一个Servlet容器)会将该请求交给FirstServlet来处理(@WebServlet(urlPatterns = "/")提供了映射关系)。

另外对于这个url的组成其实就是我们在pom.xml配置的 <finalName>,再加上FirstServlet中的@WebServlet(urlPatterns = "/")组成的。

上述代码已经上传到github,github地址为:https://github.com/wenjing-bonnie/build-spring.git

3.实际的web应用

当然在一个web应用中,是有许多个Servlet组成的,每个Servlet都会映射到一个路径。所以在开发一个完整的web应用,在web页面相关的业务逻辑这一部分中,其实可以细分成几个过程:

  • (1)不同的路径映射对应的不同的Servlet;

在每个Servlet处理业务逻辑的时候,其实也可以细分成过程:

1)从HttpServletRequest 中读取请求参数;

2)处理复杂的业务逻辑:要有读写数据库的公共操作类,要有数据库的每张表对应着一些封装类,要有针对这些表的操作的封装类,更多的是在这一个Servlet可能涉及到多个数据库表的操作,也就意味着需要引入多个表的操作类;

3)将响应数据写入到HttpServletResponse,响应数据又可以看出是一些供浏览器显示的数据(前面提到的例子中可能响应数据仅仅就是为了显示一个字符串,但在实际开发中会有更多跟页面相关的渲染,例如jsp);

显然在这个过程中会出现许多类实例的实例化和加载,以及这些类实例的生命周期的管理,并且在一个Servlet中还可以抽象成一种Model-View-Controller的设计模式。

  • (2)web服务器根据路径映射规则,将不同路径转发到对应的Servlet,该转发功能通常由服务端Dispatcher完成。

那么网络通信以及网络提供给业务层调用的功能就有Tomcat来完成。对比之前在小白新手web开发简单总结(一)-什么是Tomcat小白新手web开发简单总结(二)-什么是web.xml,这些过程似乎都有了专门的对应:

  • (1)Tomcat就是一个Servlet容器,用来实例化Servlet来进行处理请求和响应。Tomcat的Connector负责与浏览器来建立连接,接收浏览器发送过的请求以及将响应返回给浏览器;
  • (2)Tomcat中的Container中的Engine用来实例化Servlet,管理Servlet的生命周期,完成底层的网络通信;
  • (3)在web.xml中注册了DispatcherSerlvet,用来将浏览器发送过来的请求映射到对应路径的处理类中。

现在看来,对于web应用开发的一些知识点开始明朗起来。

三 web应用开发的断点调试

从上面一个简单的例子看到一个web应用开发,其实就是编写Servlet来处理浏览器发送过来的Http请求,当然我们需要将最终的这些Servlet按照既定的规则打包成war包,通过Tomcat来加载war包,并运行这些Servlet。

在一个简单的web应用实例中提到的上面的第六步和第七步,我们需要通过IDEA打包成war包,并且还要通过本地安装的Tomcat来启动war包,那么如果断点调试呢?其实我们可以Tomcat也是一个java程序,通过.startup.sh 来启动Tomcat,其实就是启动JVM并执行Tomcat的main()方法,并且加载war包之后初始化Servlet,从而对浏览器提供服务。其实我们完全可以通过代码的形式来完成一个Tomcat启动web项目。

(1)还是上面的项目代码,我们将javax.servlet换成Tomcat的相关依赖:

        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-core</artifactId>
            <version>${tomcat.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <version>${tomcat.version}</version>
        </dependency>

(2)增加Tomcat实例化的main()方法


public class FirstServletTest {
    public static void main(String[] args) throws LifecycleException {
        //创建Tomcat
        Tomcat tomcat = new Tomcat();
        tomcat.setPort(Integer.getInteger("port", 8080));
        tomcat.getConnector();
        //创建webapp
        Context context = tomcat.addWebapp("", new File("src/main/webapp").getAbsolutePath());
        WebResourceRoot resources = new StandardRoot(context);
        DirResourceSet set = new DirResourceSet(resources, "/WEB-INF/classes", new File("target/classes").getAbsolutePath(), "/");
        resources.addPreResources(set);
        context.setResources(resources);
        //启动Tomcat
        tomcat.start();
        tomcat.getServer().await();
    }
}

(3)运行main()方法,然后在IDEA中下面就会显示,表示嵌入式的Tomcat已经成功启动,Tomcat会自动的将本工程放置到根目录,可直接通过http://localhost:8080/?count=2进行访问到对应的Servlet

二月 08, 2021 2:00:25 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
二月 08, 2021 2:00:25 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
二月 08, 2021 2:00:25 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.36]
二月 08, 2021 2:00:25 下午 org.apache.catalina.startup.ContextConfig getDefaultWebXmlFragment
信息: No global web.xml found
二月 08, 2021 2:00:27 下午 org.apache.jasper.servlet.TldScanner scanJars
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
二月 08, 2021 2:00:27 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]

这样就可以轻松的将一个项目通过 运行FirstServletTest的main()的方式来断点调试项目。但是在一个实际的web应用开发中,不知道是不是通过这种方式来断点调试,还需要自己再去学习与研究。

代码github地址为:https://github.com/wenjing-bonnie/build-spring.git

四 总结

通过这个简单的web应用开发的实例,对比前面小白新手web开发简单总结(一)-什么是Tomcat小白新手web开发简单总结(二)-什么是web.xml两篇的总结,简单在总结下自己现在清晰的东西:

  • 1.一个web应用开发的项目通过maven打包成war包,运行在一个支持Servlet的web服务器;
  • 2.Tomcat就是一个支持Servlet的web服务器,每次在一个web应用服务上线的时候,应该就是将war包放到安装到服务器的Tomcat的相关目录下,并且将Tomcat启动;
  • 3.Tomcat启动之后,就会读取war包的web.xml文件,然后将里面对应的各个类实例化;
  • 4.当有浏览器有请求发送过来的时候,首先会与web服务器建立TCP连接,有浏览器发送请求;
  • 5.Tomcat接收到请求之后,会有DispatcherServlet进行根据路径匹配到对应的处理类;
  • 6.处理完之后的响应发送给浏览器,浏览器负责将数据进行显示
  • 7.HttpServlet不需要关心底层TCP等相关的网络逻辑,只需要从HttpServletRequest 取得请求参数,经过业务逻辑之后,将处理完之后的数据写入到HttpServletResponse即可。

另外记录一下关于Servlet的几个知识点:在向HttpServletResponse写入响应数据的时候,可以指定浏览器是重定向还是转发

  • 1.重定向

当浏览器请求一个url,服务器在处理完数据,返回给浏览器的时候,会告诉浏览器地址发生变化,需要浏览器在重新发送请求,通过下面的代码实现重定向:

  String redirectToUrl = "/xxxx";
   // 发送重定向响应:
   resp.sendRedirect(redirectToUrl);

浏览器接收到如下响应:

HTTP/1.1 302 Found
Location: /xxxx

会根据Location返回的 url,重新发送一个新的请求。那么在浏览器中看到是两个请求。当然重定向又分为临时重定向(302响应)和永久重定向(301响应)。两者区别在于永久重定向,浏览器会换成Location发送过来的url,在下一次在请求之前的url的时候,会直接发送Location对应的url。在代码中通过

// HttpServletResponse.SC_MOVED_PERMANENTLY:301
//HttpServletResponse.SC_FOUND:302
resp.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 
resp.setHeader("Location", "/xxxx");
  • 2.转发

转发指的是内部转发,当一个Servlet处理一个浏览器发送过来的请求的时候,自己本身不去处理,而是转发给另外一个Servlet来处理。代码中通过实现:

req.getRequestDispatcher("/xxxx").forward(req, resp);

后续请求处理实际是交给了"/xxxx"对应的Servlet来处理。

相比较于重定向而言,这个转发仅仅是服务器内部完成,对于浏览器来说,只会发出一个请求,本身不需要做任何处理,在浏览器中始终只有一个url。

这几天每天都很充实,加油!!!!!下次在看下小白新手web开发简单总结(四)-web应用开发中的MVC

猜你喜欢

转载自blog.csdn.net/nihaomabmt/article/details/113752940