java EE /servlet/创建web项目和实现流程

Web基础

我们访问网站,使用App时,都是基于Web这种Browser/Server模式,简称BS架构,它的特点是,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取Web页面,并把Web页面展示给用户即可。
Web页面具有极强的交互性。由于Web页面是用HTML编写的,而HTML具备超强的表现力,并且,服务器端升级后,客户端无需任何部署就可以使用到新的版本,因此,BS架构升级非常容易。

简略介绍HTTP协议:

在Web应用中,浏览器请求一个URL,服务器就把生成的HTML网页发送给浏览器,而浏览器和服务器之间的传输协议是HTTP,所以:

  • HTML是一种用来定义网页的文本,会HTML,就可以编写网页;
  • HTTP是在网络上传输HTML的协议,用于浏览器和服务器的通信。

==HTTP协议是一个基于TCP协议之上的请求-响应协议,==它非常简单,我们先使用Chrome浏览器查看新浪首页,然后选择View - Developer - Inspect Elements就可以看到HTML:
在这里插入图片描述

切换到Network,重新加载页面,可以看到浏览器发出的每一个请求和响应:
在这里插入图片描述
对Browser来说,请求页面的流程如下:

  • 与服务器建立TCP连接;
  • 发送HTTP请求;
  • 收取HTTP响应,然后把网页在浏览器中显示出来。

浏览器发送的http请求

浏览器发送的HTTP请求如下:

GET / HTTP/1.1
Host: www.sina.com.cn
User-Agent: Mozilla/5.0 xxx
Accept: */*
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8

其中,第一行表示使用GET请求获取路径为/的资源,并使用HTTP/1.1协议,从第二行开始,每行都是以Header: Value形式表示的HTTP头,比较常用的HTTP Header包括:

  • Host: 表示请求的主机名,因为一个服务器上可能运行着多个网站,因此,Host表示浏览器正在请求的域名;
  • User-Agent: 标识客户端本身,例如Chrome浏览器的标识类似Mozilla/5.0 … Chrome/79,IE浏览器的标识类似Mozilla/5.0 (Windows NT …) like Gecko;
  • Accept:表示浏览器能接收的资源类型,如text/*,image/或者/*表示所有;
  • Accept-Language:表示浏览器偏好的语言,服务器可以据此返回不同语言的网页;
  • Accept-Encoding:表示浏览器可以支持的压缩类型,例如gzip, deflate, br。

服务器的响应

服务器的响应如下:

HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 21932
Content-Encoding: gzip
Cache-Control: max-age=300
<html>...网页数据...

响应解析:
第一行:
服务器响应的第一行总是版本号+空格+数字+空格+文本,数字表示响应代码,其中2xx表示成功,3xx表示重定向,4xx表示客户端引发的错误,5xx表示服务器端引发的错误。数字是给程序识别,文本则是给开发者调试使用的

常见响应代码:

200 OK:表示成功;
301 Moved Permanently:表示该URL已经永久重定向;
302 Found:表示该URL需要临时重定向;
304 Not Modified:表示该资源没有修改,客户端可以使用本地缓存的版本;
400 Bad Request:表示客户端发送了一个错误的请求,例如参数无效;
401 Unauthorized:表示客户端因为身份未验证而不允许访问该URL;
403 Forbidden:表示服务器因为权限问题拒绝了客户端的请求;
404 Not Found:表示客户端请求了一个不存在的资源;
500 Internal Server Error:表示服务器处理时内部出错,例如因为无法连接数据库;
503 Service Unavailable:表示服务器此刻暂时无法处理请求。

从第二行开始
服务器每一行均返回一个HTTP头。服务器经常返回的HTTP Header包括:

Content-Type:表示该响应内容的类型,例如text/html,image/jpeg;
Content-Length:表示该响应内容的长度(字节数);
Content-Encoding:表示该响应压缩算法,例如gzip;
Cache-Control:指示客户端应如何缓存,例如max-age=300表示可以最多缓存300秒。

HTTP请求和响应都由HTTP Header和HTTP Body构成,(区分HTTP Header和HTTP Body)其中HTTP Header每行都以\r\n结束。如果遇到两个连续的\r\n,那么后面就是HTTP Body。浏览器读取HTTP Body,并根据Header信息中指示的Content-Type、Content-Encoding等解压后显示网页、图像或其他内容。

通常浏览器获取的第一个资源是HTML网页,在网页中,如果嵌入了JavaScript、CSS、图片、视频等其他资源,浏览器会根据资源的URL再次向服务器请求对应的资源。

sevlet

在JavaEE平台上,处理TCP连接,解析HTTP协议这些底层工作统统扔给现成的Web服务器去做,我们只需要把自己的应用程序跑在Web服务器上。为了实现这一目的,JavaEE提供了Servlet API,我们使用Servlet API编写自己的Servlet来处理HTTP请求,Web服务器实现Servlet API接口,实现底层功能:
在这里插入图片描述

Servlet 本身不能独立运行,需要在一个web应用中运行的
而一个web应用是部署在tomcat中的
所以开发一个servlet需要如下几个步骤

  • 创建web应用项目
  • 编写servlet代码
  • 部署到tomcat中

本例使用Eclipse EE版 结合独立的 tomcat进行一次java普通项目的创建。
这样做的好处是,通过最原始的方式创建一个web应用,可以掌握最基本的知识。

结合独立的 tomcat进行一次java普通项目的创建

1.File->New->Other->Java->Java Project

输入名称j2ee
这样就创建一个单纯的基于java的项目
注意: 必须 放在 e:\project\j2ee目录下,后续配置是基于这个目录进行
注意:不要使用如下方式
File->New->Other-Web->Dynamic Web Project
这是eclipse ee创建项目的方式,它会把各种tomcat,相关配置文件的生成都自动做掉了。 而这些细节,恰恰就是你需要学习和掌握的。 所以对于初学者不建议使用这种方式。

2.导入必须的servlet-api.jar包
因为是开发Servlet所以需要用到 servlet-api.jar 这个包里的相关类。
servlet-api.jar 包位于 D:\tomcat\lib\servlet-api.jar
或者从本网页的右侧下载
导入办法:
右键点击项目(或者点上面的project) -> properties -> Java Build Path ->Libraries -> Add External JARs
3.编写HelloServlet
创建 HelloServlet(在Eclipse中创建一个普通类的方式:菜单->File->New->Class)
注意:eclipse创建的时候会自带一个包名j2ee,不要使用这个包名,让包名置空
在这里插入图片描述
HelloServlet继承了 HttpServlet,并且提供了一个doGet方法
后续测试该类的时候,会直接在浏览器输入地址

http://127.0.01/hello

在浏览器中输入地址提交数据的方式是GET
所以该Servlet需要提供一个对应的doGet方法
参考GET和POST的区别

get和post的区别
get
是form默认的提交方式
如果通过一个超链访问某个地址,是get方式
如果在地址栏直接输入某个地址,是get方式
提交数据会在浏览器显示出来
不可以用于提交二进制数据,比如上传文件
post
必须在form上通过 method=“post” 显示指定
提交数据不会在浏览器显示出来
可以用于提交二进制数据,比如上传文件

HelloSevlet 代码:

import java.io.IOException;
import java.util.Date;
 
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class HelloServlet extends HttpServlet{
 
    public void doGet(HttpServletRequest request, HttpServletResponse response){
         
        try {
            response.getWriter().println("<h1>Hello Servlet!</h1>");
            response.getWriter().println(new Date().toLocaleString());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
     
}

3.配置web.xml

首先在j2ee下创建目录web
接着再创建目录web/WEB-INF
然后在WEB-INF目录中创建 web.xml
web.xml提供路径与servlet的映射关系
把/hello这个路径,映射到 HelloServlet这个类上

<servlet> 标签下的 <servlet-name><servlet-mapping> 标签下的 <servlet-name> 必须一样
<servlet-name><servlet-class>可以不一样,但是为了便于理解与维护,一般都会写的一样。 一目了然
'web.xml代码:'
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
 
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
 
</web-app>

4:指定项目输出到classes目录
首先在WEB-INF下创建classes目录–>把项目的class文件输出由原来的 j2ee/bin 设置到 j2ee/web/WEB-INF/classes
步骤:
项目右键->properties->Java Build Path->Source->右下角的 Brower-> 指定位置是 j2ee/web/WEB-INF/classes。

为什么要有这一步?
在ecilpse中默认输出的class是在bin目录下,但是tomcat启动之后,在默认情况下,不会去bin目录找这些class文件,而是到WEB-INF/classes这个目录下去寻找。
所以通过这一步的配置,使得eclipse的class文件输出到WEB-INF/classes目录下,那么这样就和tomcat兼容了。

5:配置tomcat的server.xml 中的<context

为了把 j2ee/web 这个目录部署到tomcat中,进行如下操作:
打开tomcat/conf/sever.xml
<Host name="localhost" 。。。 下面加一句

<Context path="/" docBase="e:\\project\\j2ee\\web" debug="0" reloadable="false" />

path="/" 就表示直接通过 http://127.0.0.1/hello 就可以访问网页了。(这个hello是servlet-mapping里面url-pattern标签设置的,也可以设置为别的内容)
如果设置为

<Context path="/j2ee" docBase="e:\\project\\j2ee\\web" debug="0" reloadable="false" />

那么表示需要通过 http://127.0.0.1/j2ee/hello才能访问.

6.删除tomcat webapps下的ROOT目录顶折纠问
在上一步部署web的时候server.xml中的path 配置为 "/" 与 webapps下的ROOT目录冲突了
所以要删除ROOT目录,如果没有就不用删除了
重启tomcat,访问http://127.0.0.1/hello

获取参数

本例通过登录行为,演示servlet如何获取从浏览器提交的账号密码

创建 login.html

在web上右键 -> New ->File–>创建一个 login.html文件
然后添加一个form元素
action="login" 标题会提交到login路径,login路径在后续步骤会映射到LoginServlet
method="post" post方式表示提交的密码信息在浏览器地址栏看不到
然后准备账号和密码的input元素(因为要提交两个数据,在servlet端为了区分哪个是账号,哪个是密码,要给这两个input元素的name属性分别叫做name和password。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
  
<form action="login" method="post">
账号: <input type="text" name="name"> <br>
密码: <input type="password" name="password"> <br>
<input type="submit" value="登录">
</form>
  
</body>
</html>

创建 LoginServlet

创建一个LoginServlet
因为浏览器中的form的method是post,所以LoginServlet需要提供一个doPost方法
在doPost方法中,通过request.getParameter 根据name取出对应的账号和密码
然后用System.out.println() 打印在控制台
注 这里是打印在控制台,并没有在网页上输出

import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
  
public class LoginServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String name = request.getParameter("name");
        String password = request.getParameter("password");
  
        System.out.println("name:" + name);
        System.out.println("password:" + password);
    }
}

映射LoginServlet到路径login

在web.xml中新增映射:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
 
    <servlet>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
     
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>LoginServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>   
 
</web-app>

在页面提交数据顶折纠问
首先重启tomcat–然后访问页面

http://127.0.0.1:8080/login.html(我用的官网的Tomca)

输入账号密码,提交
然后在tomcat的窗口,就可以看到提交的账号和密码了。
注 不是在浏览器上看到这个提交的数据,浏览器上要看到tomcat的反馈数据,需要通过响应来实现。
在这里插入图片描述

小结

在浏览器中输入地址提交数据的方式是GET (因为是出入地址,而不是提交,提交,然后登录跳转页面这种的话,需要隐藏提交内容(密码字段啥的)就要用Post)
servlet里面需要用doGet(提交的话就是doPost),,给浏览器

 protected void doGet/doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {}

。。对话了解doPost/doGet
在这里插入图片描述
页面是根据表单中的get/post去调用对应servlet中的doGet/doPost方法的。get/post用哪个,主要是看信息能不能出现在地址栏(一个网页可以同时有get/Post,比如网页上有两个表单,但是对应的servlet也要同时有doGet/doPost)
直接在地址栏上输入地址,那就是Get方法,如果你访问的地址的servlet没有设置doGet方法,那就访问错误,如下图。只有当你的servlet 有doGet方法时,才会回应你。
在这里插入图片描述
设置为service时,servlet 无论表单是Get还是Post,都会判断。比如直接地址栏输入http://127.0.0.1:8080/PageLogin?name=admin&password=123,尽管我的表单是Post,还是显示登录成功了,不安全

(在上面例子中)
request.getParameterresponse.getWriter().println("<h1>Hello Servlet!</h1>");
request.getParameter 是doPost()中,向服务器请求数据,这个数据是前端界面login.html提交的。
response.getWriter().println("<h1>Hello Servlet!</h1>");是doGet中服务器向浏览器回应的
以发送响应为例,我们只需要设置正确的响应类型,然后获取PrintWriter,写入响应即可。
~~ ~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~·(自我感觉)
LoginServlet.java是处理响应的…有前端界面login,login.html提交数据给服务器,LoginServlet.java,是服务器在处理数据,请求或者响应数据,但是需要在web.xml中映射LoginServlet到路径login(login表单中action的指向)
~~++++++++++++++++++++++++++++++++

一个最简单的Servlet:

// WebServlet注解表示这是一个Servlet,并映射到地址/:
@WebServlet(urlPatterns = "/")
public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 设置响应类型:
        resp.setContentType("text/html");
        // 获取输出流:
        PrintWriter pw = resp.getWriter();
        // 写入响应:
        pw.write("<h1>Hello, world!</h1>");
        // 最后不要忘记flush强制输出:
        pw.flush();
    }
}

一个Servlet总是继承自HttpServlet,然后覆写doGet()doPost()方法。
注意到doGet()方法传入了HttpServletRequestHttpServletResponse两个对象,分别代表HTTP请求和响应。

Serlvet接口只定义了一个服bai务方法就是service,而duHttpServlet类实现了该方法并且要求调用下列方法之一:
doGet:处理GET请求
doPost:处理POST请求
1、客户端(一般指浏览器)生成的方式
get:form中method属性为get时;或者直接在URL地址栏中输入URL,需要传递参数时,直接在URL后面拼接“?name=张三&age=18”这样的查询参数字符串;
post:form中method属性为post。
2、客户端数据传送方式
get:表单数据存放在URL地址后面。所有get方式提交时HTTP中没有消息体;
post:表单数据存放在HTTP协议的消息体中以实体的方式传送到服务器。
3、服务器获取数据方式
get:服务器采用Servlet中的doGet来获取变量的值;
post:服务器采用Servlet中的doPost来获取数据。
4、传输的数据量
get:数据量长度有限制,一般不超过2kb。因为是参数传递,且在地址栏中,故数据量有限制;
post:适合大规模的数据传送。因为是以实体的方式传送的

我们使用Servlet API时,并不直接与底层TCP交互,也不需要解析HTTP协议,因为HttpServletRequestHttpServletResponse就已经封装好了请求和响应。以发送响应为例,我们只需要设置正确的响应类型,然后获取PrintWriter,写入响应即可。
必须先启动Web服务器,再由Web服务器加载我们编写的HelloServlet,这样就可以让HelloServlet处理浏览器发送的请求。

返回响应

根据浏览器提交的账号密码返回登录成功或者失败
这一步本来应该通过访问数据库来实现,这里简化一下,直接在内存中进行校验
如果账号是 admin,密码是123, 就返回登录成功,否则返回登录失败

LoginServlet

根据账号密码,创建对应的html字符串。
然后通过response.getWriter().println() 发送到浏览器。
注: 比较的时候把常量字符串"admin" "123"放前面,因为用户可能没有输入账号密码就提交,servlet会获取到null。 这样就规避了空指针异常的问题。
注: 这里输出的响应是success和fail,不是中文。 如果使用中文浏览器有可能看到乱码。

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginServlet extends HttpServlet {
  
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
  
        String name = request.getParameter("name");
        String password = request.getParameter("password");
  
        String html = null;
  
        if ("admin".equals(name) && "123".equals(password))
            html = "<div style='color:green'>success</div>";
        else
            html = "<div style='color:red'>fail</div>";
  
        PrintWriter pw = response.getWriter();
        pw.println(html);
  
    }
  
}

然后重启Tomcat,再访问http://127.0.0.1:8080/login.html

必须重启Tomcat,然后再次访问http://127.0.0.1:8080/login.html

代码修改之后没有重新编译,重新编译class文件之后,在重启tomcat,访问网址,然后输入账号密码,浏览器就会有显示了

调用流程总结

流程图

大体思路图就是这样,接下来对思路图里的每个环节具体讲解
在这里插入图片描述
补充:

  • 返回的html,即/login(命名的一个新的html)
  • 根据页面login.html提交信息的时候带的method=“post”,去调用对应的doPost方法。
  • 表单中的action=“login”,是把数据传给了那个地址(/login),然后再到web.xml中查看这个地址和那个servlet 绑定的,然后再执行绑定的servlet,再有servlet 返回给浏览器
  • LoginServlet.java 解析后,tomcat拿到被Servlet修改过的response,根据这个response生成html 字符串,然后再通过HTTP协议,这个html字符串,回发给浏览器,浏览器再根据HTTP协议获取这个html字符串,并渲染在界面上。
    这样在效果上,浏览器就可以看到Servlet中生成的字符串了
  • 在这里插入图片描述
    对于服务器来说,
    第二步,Browser发送Http请求,服务器用request.getParameter(),请求了浏览器发来的数据,
    第三步,Browser收取HTTP响应,是服务器用response.getWriter()发送响应给了浏览器

login.html

首先访问

http://127.0.0.1:8080/login.html

打开一个静态的html页面,在这个页面中可以通过form,以post的形式提交数据

/login路径

在上一步的login.html中,用form,把账号和密码,提交到/login这个路径,并且附带method="post"

找到对应的Servlet

tomcat(服务器)接受到一个新的请求:

http://127.0.0.1/login

其路径是/login,接着就到配置文件web.xml进行匹配,发现/login,对应的Servlet类是 LoginServlet
接下来的工作,就会基于这个LoginServlet进行。

在这里插入图片描述

实例化Servlet对象

Tomcat 定位到了LoginServlet后,发现并没有LoginServlet的实例存在,于是就调用LoginServlet的public无参的构造方法LoginServlet()实例化一个LoginServlet对象以备后续使用

调用doGet或者doPost

Tomcat从上一步拿到了LoginServlet的实例之后,根据页面login.html提交信息的时候带的method=“post”,去调用对应的doPost方法。

request获取参数

接着流程进入了doPost方法中,

protected void doPost(HttpServletRequest request, HttpServletResponse response){
...
}

在这个方法中,通过参数request,把页面上传递来的账号和密码信息取出来

String name = request.getParameter("name");
String password = request.getParameter("password");

response设置响应

接着,根据账号和密码是否正确(判断是否是admin和123), 创建不同的html字符串。
然后把html字符串通过如下方式,设置在了response对象上。

PrintWriter pw = response.getWriter();
pw.println(html);

到这里,Servlet的工作就做完了。

tomcat把html传递给浏览器

在Servlet完成工作之后,tomcat拿到被Servlet修改过的response,根据这个response生成html 字符串,然后再通过HTTP协议,这个html字符串,回发给浏览器,浏览器再根据HTTP协议获取这个html字符串,并渲染在界面上。
这样在效果上,浏览器就可以看到Servlet中生成的字符串了

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个错误通常在 Java Web 应用程序中出现,它表示在运行时找不到指定的类 jakarta.servlet.ServletContextListener。 这个问题通常是由于缺少相关的依赖库或者版本冲突引起的。要解决这个问题,你可以尝试以下几个步骤: 1. 确保你的项目中包含了正确的 Servlet API 依赖库。你可以通过 Maven 或者 Gradle 等构建工具来添加依赖。例如,在 Maven 中可以添加以下依赖: ```xml <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <version>4.0.4</version> <scope>provided</scope> </dependency> ``` 2. 检查你的项目中是否存在其他版本的 Servlet API 相关的依赖库,这可能会导致冲突。你可以通过 Maven 或者 Gradle 的依赖树来排查冲突。 3. 如果你使用的是老版本的容器(如 Tomcat 8 或以下版本),则需要使用旧版本的 Servlet API。在这种情况下,你应该使用 javax.servlet.ServletContextListener 而不是 jakarta.servlet.ServletContextListener。确保使用了正确的 API 类。 4. 如果你使用的是较新的 Jakarta EE(旧名 Java EE)容器,例如 Tomcat 10 或以上版本,那么你需要确保使用了 jakarta.servlet.ServletContextListener 类。在这种情况下,你可能需要更新你的容器或者使用兼容 Jakarta EE 的版本。 总之,要解决这个问题,你需要确保正确引入 Servlet API 的依赖,并避免版本冲突。如果问题仍然存在,你可以提供更多关于你的项目环境和依赖的详细信息,以便更好地帮助你解决问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值