基本概念
C/S架构(客户端/服务器模式)
这种结构将需要处理的业务合理地分配到客户端和服务器端,客户端通常负责完成与用户的交互任务,服务器通常负责数据的管理(增删改查)
如:QQ,英雄联盟,迅雷
优点:
- 客户端的界面和功能都是比较丰富的,因为其实可以理解为部分业务交给客户端完成
- 应用服务器(安装在硬件服务器上的服务器软件)的负荷较轻
- 响应速度较快,因为只有客户端和服务器这一层交互
缺点: - 适用面窄(玩英雄联盟需下载客户端),用户群固定
- 维护和升级的成本高,所有的客户端都需要更新版本
B/S 架构(浏览器/服务器模式)
该结构将系统功能实现的主要业务逻辑集中到服务器端,极少数业务逻辑在浏览器实现,浏览器通常负责完成与用户的交互任务,服务器通常负责数据的管理
如:淘宝,JD等
优点:
- 无需安装客户端,只要有浏览器即可
- 适用面广,用户群不固定
- 通过权限控制实现多客户访问的目的,交互性较强
- 维护和升级的成本低,无需更新所有客户端版本
缺点 - 应用服务器的负荷较重
- 浏览器的界面和功能想要达到客户端的丰富程度需要花费大量的成本
- 在跨浏览器上不尽如人意,适配比较麻烦
Java大部分会用于B/S架构的开发
JavaWeb的概念
Web这里表示互联网上供外界访问的资源
互联网上供外界访问的资源主要分为以下两种:
- 静态资源:主要指Web页面中供人们浏览的数据始终是不变。
- 动态资源:主要指Web页面中供人们浏览的数据由程序产生,不同时间点访问页面看到的内容各不相同
JavaWeb主要指使用Java语言进行动态Web资源开发技术
现在基本的B/S架构基本示意图
HTTP协议(超文本传输协议)
HTTP协议的概念
HTTP协议是一种应用层协议,是用来规范浏览器与Web服务器之间如何通讯的数据格式,主要涉及浏览器的发请求格式和服务器的响应格式
http和https其实都是通信协议,HTTP默认的端口号为80,HTTPS默认的端口号为443。HTTP协议通常承载于TCP协议之上
HTTP请求格式
客户端发送一个HTTP请求到服务器的请求消息主要包括:请求行、请求头、空白行和请求体:
- 请求行用来说明请求类型和要访问的资源以及所使用的HTTP版本,格式为:
请求类型 请求的路径 协议的版本(1.1)
- 请求头是紧接着请求行之后的部分,用来说明服务器要使用的附加信息,格式 (key:value):
主机 请求长度 请求的浏览器相关信息
- 空白行就是请求头部的空行,即使后面的请求数据为空则必须有空行
- 请求体也叫请求数据,可以添加任意的其他数据
HTTP例子
POST /task01_demo01/demo1.html HTTP/1.1 //请求行,post类型
Host: localhost:8088 //请求的服务器的ip和端口号
Content-Length: 21 //数据内容长度
Cache-Control: max-age=0 //有效期
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) //主机浏览器信息
name=scott&pwd=123456//请求体 用户名 密码
HTTP响应格式
通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息,主要包括:响应行、响应头、空白行和响应体
- 响应行用来说明HTTP协议版本号和状态码以及状态消息,格式如下:
协议的版本(1.0 1.1) 状态码 (200 成功 404 路径错误 500 服务错误) 状态信息
- 响应头用来说明客户端要使用的一些附加信息,格式(key:value)
- 空白行就是响应头部的空行,即使后面的请求数据为空则必须有空行
- 响应体用来服务器返回给客户端的文本信息,即附加的数据内容
例子
HTTP/1.1 200 OK //200处理成功 响应行
Content-Type: text/html //内容类型
Content-Length: 588 //内容长度
Date: Thu, 08 Sep 2021 12:59:54 GMT //日期
<html><head><title>示例1</title></head>
<body><h1>这是一个HTML页面</h1></body>
</html>
Tomcat服务器
基本概念
Tomcat 服务器是一个开源的轻量级Web应用服务器,在中小型系统和并发量小的场合下被普遍使用,是开发和调试Servlet、JSP 程序的首选
下载安装
这里下载了8.55版本
- bin主要存放二进制可执行文件和脚本。
- conf 主要存放各种配置文件。
- lib 主要用来存放Tomcat运行需要加载的jar包。
- logs 主要存放Tomcat在运行过程中产生的日志文件。
- temp 主要存放Tomcat在运行过程中产生的临时文件。
-webapps 主要存放应用程序,当Tomcat启动时会去加载该目录下的应用程序。 - work 主要存放tomcat在运行时的编译后文件,例如JSP编译后的文件
启动与关闭
-
启动方式:使用bin目录下的批处理文件startup.bat来启动Tomcat服务器,若出现一个毫秒数说明启动成功
也可在网页给tomcat发送一个http请求
http://localhost:8080/
localhost指的是本机
其中8080是默认端口号 -
关闭方式 :使用bin目录下的批处理文件shutdown.bat来关闭Tomcat服务器,或者直接叉掉
-
乱码解决方式:
UTF-8改成GBK
配置环境变量CATALINA_HOME可让Tomcat服务器可以在任意路径启动
配置文件
- server.xml文件是服务器的主配置文件,可以设置端口号、设置域名或IP、默认加载的项目、请求编码等
如果改port成80,则无需写端口号就能访问
- tomcat-users.xml文件用来配置管理Tomcat服务器的用户与权限
配置完成后
Tomcat服务器中项目的部署和资源访问
在Tomcat的webapps下部署index.html进服务器
浏览器发送HTTP请求给服务器
结果如下:
IDEA创建Web项目
这里也配置好了Tomcat服务器
IDEA中Tomcat服务器的相关配置
URL是访问路径
启动服务器和访问项目
Servlet的概念和使用
基本概念
-
Servlet就是Java Servlet的简称,称为小服务程序或服务连接器,是Java语言编写的服务器端程序,换句话说,Servlet就是运行在服务器上的Java类
-
Servlet用来完成B/S架构下客户端请求的响应处理,也就是交互式地浏览和生成数据,生成动态Web内容
Servlet的编程步骤
- 建立一个Java Web Application项目并配置Tomcat服务器
- 自定义类实现Servlet接口或继承 HttpServlet类(推荐) 并重写service方法
service类的主要作用是处理浏览器的请求
这里创建一个HelloServlet类并实现Servlet接口
public class HelloServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("接收到了浏览器的请求并做出了响应!");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
- 将自定义类的信息配置到 web.xml文件并启动项目,配置方式如下:
就是对web.xml文件进行配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 进行servlet配置 -->
<servlet>
<!-- 对servlet起别名 习惯上就使用类名 -->
<servlet-name>HelloServlet</servlet-name>
<!-- 指定上述别名所对应的servlet类 -->
<servlet-class>com.example.demo02.HelloServlet</servlet-class>
</servlet>
<!-- 进行servlet的映射配置-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<!-- 配置浏览器访问地址-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
启动服务器并部署项目
启动服务器后,输入/hello
http://localhost:8080/task01_demo1_war_exploded/hello
则有
Servlet接口
javax.servlet.Servlet接口用于定义所有servlet必须实现的方法
GenericServlet类
javax.servlet.GenericServlet类主要用于定义一个通用的、与协议无关的servlet,该类实现了Servlet接口
具体实现:在task01_demo1module的main文件下的java文件中创建HelloServlet2类继承自GenericServlet类
public class HelloServlet2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("继承GenericServlet类的方式来创建Servlet");
}
}
然后在web.xml文件中修改相应配置即可
输入http://localhost:8080/task01_demo1_war_exploded/hello2
HttpServlet类(推荐使用这种方式)
- javax.servlet.http.HttpServlet类是个抽象类并继承了GenericServlet类
- 用于创建适用于网站的HTTP Servlet,该类的子类必须至少重写一个方法
这里重写servlet方法
public class HelloServlet3 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这是采用继承HttpServlet类的方式创建");
}
}
配置好web.xml后http://localhost:8080/task01_demo1_war_exploded/hello3
Servlet生命周期
HttpServlet中常用方法有:
(super是调用父类的版本)
修改HelloServlet3为以下:
public class HelloServlet3 extends HttpServlet {
public HelloServlet3() {
System.out.println("构造方法调用了");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("这是采用继承HttpServlet类的方式创建");
}
@Override
public void destroy() {
System.out.println("销毁操作开始");
}
@Override
public void init() throws ServletException {
System.out.println("初始化操作开始");
}
}
只有当
http://localhost:8080/task01_demo1_war_exploded/hello3
访问hello3时候才有以下语句
当我们刷新网页时候是不会重新调用构造和初始化方法的
停止服务器时才会执行destory(),与init()对应
- 构造方法只被调用一次,当第一次请求Servlet时调用构造方法来创建Servlet的实例。
- init方法只被调用一次,当创建好Servlet实例后立即调用该方法实现Servlet的初始化。
- service方法被多次调用,每当有请求时都会调用service方法来用于请求的响应。
- destroy方法只被调用一次,当该Servlet实例所在的Web应用被卸载前调用该方法来释放当前占用的资源
Servlet的简写方式
可得
@WebServlet(name = "HelloServlet4", value = "/HelloServlet4")
public class HelloServlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
其中@WebServlet是注解,name是注解中的属性(成员),HelloServlet4是成员的值
WebServlet这个注解中属性与web.xml中的值对应
如
- name对应
<servlet-name>
- urlPatterns对应
<url-pattern>
因为注解中已完成了配置文件web.xml的工作,所以这里无需再在web.xml进行配置
@WebServlet(name = "HelloServlet4",urlPatterns = "/hello4")
public class HelloServlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("使用了注解进行配置");
}
}
使用
http://localhost:8080/task01_demo1_war_exploded/hello4
上面代码中的doGet和doPost
完整代码:
@WebServlet(name = "HelloServlet4",urlPatterns = "/hello4")
public class HelloServlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Get请求方式。。。");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("Post请求方式。。。");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("使用了注解进行配置");
String method = req.getMethod();
System.out.println("获取到的请求方式为:"+method);
if("get".equalsIgnoreCase(method)){
doGet(req,resp);
}
if("post".equalsIgnoreCase(method)){
doPost(req,resp);
}
}
}
在/hello4页面中刷新一下是get请求方式
Post和Get请求
浏览器向服务器发送的请求类型主要是Post请求和Get请求
Get请求
发出GET请求的主要方式:
- 在浏览器输入URL按回车
就例如http://localhost:8080/task01_demo1_war_exploded/hello4是Get请求
- 点击
<a>
超链接
创建request.html文件用于测试
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求方式测试</title>
</head>
<body>
<!-- 测试一下超链接方式是否为Get请求-->
<a href="hello4">测试Get请求</a>
</body>
</html>
- 点击submit按钮,提交
<form method=“get”>
表单
修改request.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求方式测试</title>
</head>
<body>
<!-- 测试一下超链接方式是否为Get请求-->
<a href="hello4">测试Get请求</a>
<!--使用form表单的方式采用Get请求提交-->
<form action="hello4" method="get">
<input type="submit"/>
</form>
</body>
</html>
http://localhost:8080/task01_demo1_war_exploded/request.html
点击提交查询
两条“Get请求方式。。。”
第一条是输入url的时候,第二条是form的get表单方式
GET请求特点:
会将请求数据添加到请求URL地址的后面,只能提交少量的数据、不安全
Post请求
- 发出POST请求的方法如下:
点击submit按钮,提交<form method=“post”>
表单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求方式测试</title>
</head>
<body>
<!-- 测试一下超链接方式是否为Get请求-->
<a href="hello4">测试Post请求</a>
<!--使用form表单的方式采用Get请求提交-->
<!--<form action="hello4" method="get">-->
<!--使用form表单的方式采用Post请求提交-->
<form action="hello4" method="post">
<input type="submit"/>
</form>
</body>
</html>
- POST请求的特点:
请求数据添加到HTTP协议体中,可提交大量数据、安全性好
以后的开发中还是用post请求比较多
这样就算无论浏览器用Get还是Post,最终都调用doPost()
ServletRequest接口
-
javax.servlet.ServletRequest接口主要用于向servlet提供客户端请求信息,可以从中获取到任何请求信息
-
Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法
意思是把客户端向服务器发送的所有请求信息打包到一个对象中扔给Service。相当于一个包裹,这个包裹是ServletRequest类型的引用
常用方法
且HttpServletRequest接口是ServletRequest接口的子接口,所以有继承关系,HttpServletRequest接口可使用父接口中的方法
代码实现以上几个方法的使用
创建parameter.html先写前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>请求参数的获取和测试</title>
</head>
<body>
<form action="Parameter" method="post">
姓名:<input type="text" name="name"/><br/>
年龄:<input type="text" name="age"/><br/>
爱好:<input type="checkbox" name="hobby" value="Java"/>Java
<input type="checkbox" name="hobby" value="C"/>C
<input type="checkbox" name="hobby" value="C++"/>C++<br/>
<input type="submit" value="提交"/>
</form>
</body>
</html>
再修改配置文件
ParameterServlet继承HttpServlet类,并重写service方法
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取指定参数名称对应的参数值并打印
String name=request.getParameter("name");
System.out.println("获取到的姓名为:"+name);
String[] hobbies=request.getParameterValues("hobby");
System.out.println("获取到的爱好有:");
for(String ts:hobbies){
System.out.println(ts+" ");
}
System.out.println();
System.out.println("-----------------------------");
//2.获取所有参数的名称
Enumeration<String> parameterNames=request.getParameterNames();
System.out.print("获取到的所有参数名称为:");
while (parameterNames.hasMoreElements()){
System.out.println(parameterNames.nextElement()+" ");
}
System.out.println();
}
}
Tomcat服务器上先运行前端页面
输入数据,点提交
结果验证了所有接口的用法,就是打包给了servlet
获取参数的方式二
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request,response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.获取指定参数名称对应的参数值并打印
String name=request.getParameter("name");
System.out.println("获取到的姓名为:"+name);
String[] hobbies=request.getParameterValues("hobby");
System.out.println("获取到的爱好有:");
for(String ts:hobbies){
System.out.print(ts+" ");
}
System.out.println();
System.out.println("-----------------------------");
//2.获取所有参数的名称
Enumeration<String> parameterNames=request.getParameterNames();
System.out.print("获取到的所有参数名称为:");
while (parameterNames.hasMoreElements()){
System.out.print(parameterNames.nextElement()+" ");
}
System.out.println();
System.out.println("-----------------------------");
//3.获取请求参数名和对应值的第二种方式
Map<String,String[]> parameterMap =request.getParameterMap();
//使用Map集合中所有的键值对组成Set集合
Set<Map.Entry<String,String[]>> entries = parameterMap.entrySet();
//遍历Set集合
for(Map.Entry<String,String[]> me:entries){
System.out.print(me.getKey()+"对应的数值有:");
for(String ts:me.getValue()){
System.out.print(ts+" ");
}
System.out.println();
}
}
}
请求中其他信息的获取(浏览器信息)
ServletRequest接口中有以下两个方法
子接口HttpServletRequest接口
- javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP请求信息的功能
- 不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置
- 可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据
//获取客户端请求的其他信息(浏览器信息)
System.out.println("发送请求的客户端IP地址为:"+request.getRemoteAddr());
System.out.println("发送请求的客户端端口号为:"+request.getRemotePort());
System.out.println("请求资源的路径为:"+request.getRequestURI());
System.out.println("请求资源的完整路径为:"+request.getRequestURL());
System.out.println("请求方式为:"+request.getMethod());
System.out.println("请求的附带参数为:"+request.getQueryString());
System.out.println("请求的Servlet路径为:"+request.getServletPath());
结果为:
之前是在这里配置了Servlet路径
把请求方式改为get后重新部署
改完一定要刷新
ServletRequest和HttpServletRequest接口都是用来打包客户端向服务器发送请求的相关信息
响应信息的设置和发送
ServletResponse接口和HttpServletResponse接口
对服务器(发送给客户端)进行响应的相关信息打包
ServletResponse接口
- javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应。
- Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法
常用方法:
//向客户端浏览器发送响应数据
PrintWriter writer = response.getWriter();
writer.write("I Received!");
System.out.println("服务器发送数据成功!");
writer.close();
点击提交后,服务器向浏览器也能发送数据
在响应中加入中文
直接加入会乱码
response默认的编码方式是欧洲码表
用这个方法
完整代码如下
//向客户端浏览器发送响应数据
//设置服务器和浏览器的编码方式以及文本类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
//writer.write("I Received!");
writer.write("我接收到了!");
System.out.println("服务器发送数据成功!");
writer.close();
HttpServletResponse接口
javax.servlet.http.HttpServletResponse接口继承ServletResponse接口,以便在发送响应时提供特定于HTTP的功能
案例题目
使用Servlet获取在服务器获取一个1~100之间的随机数并发送给客户端进行显示
System.out.println("-----------------------------");
//向客户端浏览器发送响应数据
//设置服务器和浏览器的编码方式以及文本类型
response.setContentType("text/html;charset=UTF-8");
PrintWriter writer = response.getWriter();
Random ra = new Random();
int num = ra.nextInt(100)+1;
writer.write("<h1>"+num+"</h1>");
System.out.println("服务器发送数据成功!");
writer.close();
请求信息的乱码处理(重点)
Tomcat 8.5后Get请求不会出现乱码了
但是对于Post还是会有
浏览器在提交表单时,会对中文参数值进行自动编码。当Tomcat服务器接收到浏览器请求后自动解码,当编码与解码方式不一致时,就会导致乱码
解决POST接收乱码
接收之前设置编码方式: request.setCharacterEncoding(“utf-8”)
必须在调用request.getParameter(“name”)之前设置
就可以接收中文了
ServletConfig接口(熟悉)
javax.servlet.ServletConfig接口用于描述Servlet本身的相关配置信息,在初始化期间用于将信息传递给Servlet配置对象
ServletContext接口(熟悉)
- javax.servlet.ServletContext接口主要用于定义一组方法,Servlet使用这些方法与它的Servlet容器通信。
- 服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象,用于实现多个Servlet之间的信息共享和通信。
- 在Servlet中通过this.getServletContext()方法可以获得ServletContext对象