文章目录
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.getParameter
和response.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()
方法传入了HttpServletRequest
和HttpServletResponse
两个对象,分别代表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协议,因为HttpServletRequest
和HttpServletResponse
就已经封装好了请求和响应。以发送响应为例,我们只需要设置正确的响应类型,然后获取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中生成的字符串了