JavaWeb基础学习
Web
Java Web 开发是指使用 Java 技术构建动态的 Web 应用程序。它涉及到多个层次的开发,包括前端展示、业务逻辑处理和数据持久化。
Web软件架构
Web 软件架构涉及设计和组织 Web 应用程序的不同组件和层次,以确保系统的可维护性、扩展性和性能。以下是常见的 Web 软件架构组件和模式:
1. 客户端(前端)
- 用户界面(UI):包括网页设计和用户交互元素,通常使用 HTML、CSS 和 JavaScript 开发。
- 前端框架:如 React、Angular、Vue.js,用于构建动态和响应式用户界面。
- 客户端逻辑:处理用户输入、验证、动态更新页面内容等功能。
2. 服务器端(后端)
- 应用服务器:处理业务逻辑和数据处理,接收客户端请求并生成响应。常见的应用服务器包括 Apache Tomcat、Jetty、JBoss 等。
- Web 服务器:如 Apache HTTP Server、Nginx,负责接收客户端请求并将其转发给应用服务器。
3. 服务层
- 业务逻辑:处理应用程序的核心功能,如数据处理、计算和业务规则。
- 服务接口:提供与客户端或其他服务交互的 API 接口,通常使用 RESTful API 或 GraphQL。
4. 数据层
- 数据库:存储和管理应用程序的数据。包括关系型数据库(如 MySQL、PostgreSQL)和 NoSQL 数据库(如 MongoDB、Cassandra)。
- 数据访问层:负责与数据库的交互,进行数据的增删改查操作。通常使用 ORM(对象关系映射)工具,如 Hibernate、JPA。
5. 安全层
- 身份验证:验证用户的身份,确保用户是其声称的身份。常见的方法包括用户名/密码、OAuth、JWT(JSON Web Token)。
- 授权:管理用户的权限,控制用户对特定资源的访问权限。
- 数据加密:保护数据的机密性,使用 SSL/TLS 加密数据传输。
6. 缓存层
- 缓存:提高系统性能,减少数据库访问次数。常见缓存工具包括 Redis、Memcached。
- 内容分发网络(CDN):加速静态资源的分发,提高网站的加载速度,减少服务器负担。
7. 监控和日志
- 监控:实时监控应用程序和服务器的性能,检测系统健康状况。工具如 Prometheus、Grafana。
- 日志:记录应用程序的运行状态和错误信息,用于故障排查和性能分析。工具如 ELK Stack(Elasticsearch, Logstash, Kibana)。
8. 构建和部署
- 构建工具:自动化编译、测试和打包过程,如 Maven、Gradle。
- 持续集成/持续部署(CI/CD):自动化构建、测试和部署应用程序,提高开发效率和代码质量。
- 容器化:使用 Docker 容器技术部署应用程序,确保环境一致性和便于扩展。
9. 架构模式
- MVC(Model-View-Controller):将应用程序分为模型、视图和控制器三部分,分离业务逻辑和用户界面。
- 微服务架构:将应用程序拆分为多个独立的服务,每个服务负责不同的功能,彼此通过 API 进行通信。
- 单体架构:将应用程序的所有功能打包在一个单一的部署单元中,适用于小型应用程序或初期开发阶段。
Web 服务器
我们在学习与测试中,通常会使用TomCat来作为小型的Web服务器,Tomcat 是一个开源的 Servlet 容器,负责运行 Java Servlets 和 JSP(JavaServer Pages)。它实现了 Java EE(现在称为 Jakarta EE)规范中的 Servlet 和 JSP 部分,使得 Java Web 应用程序可以在其中运行。
这里便产生了一个问题,什么是Servlet?
Servlet 是 Java EE(现在称为 Jakarta EE)规范的一部分,用于创建动态 Web 应用程序的服务器端组件。它是一种 Java 类,通过实现 javax.servlet.Servlet 接口,处理客户端请求并生成响应。
通俗来讲,Servlet就是一个接口,定义了Java类被浏览器访问到(tomcat识别)的规则。
那么,我们应该学习他有哪些用法:
Servlet快速入门:
-
创建JavaEE项目
-
导入依赖
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency>
-
定义一个类,实现Servlet接口
public class ServletDemo1 extends HttpServlet
-
实现抽象类中的抽象方法
-
在web.xml中配置:
<web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.codingfuture.ServletDemo1</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
代码示例:
public class ServletDemo1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("doPost");
}
}
Servlet3.0
- 好处:
支持注解配置。可以不需要配置web.xml了
- 步骤:
- 创建JavaEE项目
- 定义一个类,实现Servlet接口
- 重写方法
- 在类上使用@WebServlet注解,进行配置
代码示例:
@WebServlet(urlPatterns = "/demo1")
@WebServlet(value = "/demo2")
@WebServlet(name = "/demo3")
@WebServlet("/demo4")
前端跳转Servlet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/servlet4" method="get">
<input name="username">
<input type="submit" value="提交">
</form>
</body>
</html>
@WebServlet("/servlet4")
public class Servlet4 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("doPost");
}
}
Servlet相关配置
- urlpartten:Servlet访问路径
- 一个Servlet可以定义多个访问路径 : @WebServlet({“/d4”,“/dd4”,“/ddd4”})
- 路径定义规则:
- /xxx:路径匹配
- /xxx/xxx:多层路径,目录结构
- *.do: 扩展名匹配
代码示例:
@WebServlet({"/d2", "/dd2", "/ddd2"})//都可以访问到
@WebServlet("/demo2/user") //多层路径
@WebServlet("/demo2/*") //通配符, *任意字符
@WebServlet("*.do") // 任意字符.do 访问
HTTP协议
HTTP(HyperText Transfer Protocol)是一种用于在客户端(如浏览器)和服务器之间传输数据的协议。它是Web通信的基础,主要用于请求和响应的交换。
HTTP协议分层模型
图片转载自:互联网协议 - 走看看
HTTP 协议可以从不同的层次进行分解和理解,但通常不直接划分为多层。我们可以从网络协议的层次结构和 HTTP 协议的设计角度来理解它的分层:
- 应用层
- HTTP协议本身:在OSI模型和TCP/IP模型中,HTTP 处于应用层。它定义了客户端和服务器之间的数据交换格式,包括请求和响应的结构、方法、状态码、头信息等。
- HTTP的请求和响应:包括 HTTP 请求方法(如 GET、POST)、状态码(如 200 OK、404 Not Found)、头信息(如 Content-Type、Authorization)和正文(body)等。
- 传输层
- TCP:在实际的数据传输中,HTTP 协议通常运行在 TCP 协议之上。TCP 提供了可靠的、面向连接的传输服务,确保 HTTP 消息的正确传输。
- TLS/SSL:当 HTTP 被加密(使用 HTTPS)时,SSL/TLS 协议在传输层提供加密和安全保障。
- 网络层
- IP:HTTP 数据包在网络中传输时,IP 协议负责将数据从源地址传输到目标地址。IP 协议位于网络层,提供了数据包的寻址和路由功能。
- 数据链路层
- 以太网/Wi-Fi等:在最底层,数据链路层协议负责在物理网络上传输数据帧,包括以太网、Wi-Fi等技术。
HTTP的基本特点
- 请求-响应模型:
- 客户端请求:客户端(如浏览器)发起HTTP请求,向服务器请求资源或服务。
- 服务器响应:服务器处理请求并返回HTTP响应,包含请求结果或错误信息。
- 无状态:
- 每个请求都是独立的,与之前或之后的请求无关。服务器不会记住客户端的状态或会话信息。
- 方法:
- GET:请求资源,通常用于获取数据。
- POST:提交数据,通常用于提交表单数据或创建资源。
- PUT:更新资源,用于替换指定资源的内容。
- DELETE:删除资源,用于请求删除指定资源。
- HEAD:类似于GET,但只请求头信息,不返回实际数据。
- OPTIONS:请求支持的HTTP方法。
- 状态码:
- 2xx:成功(如200 OK)。
- 3xx:重定向(如301 Moved Permanently)。
- 4xx:客户端错误(如404 Not Found)。
- 5xx:服务器错误(如500 Internal Server Error)。
- 头信息:
- HTTP头信息包含请求和响应的元数据,如Content-Type、Content-Length、User-Agent等,用于描述数据的格式、长度和客户端信息。
- 协议版本:
- HTTP/1.0:较早的版本,支持基础功能。
- HTTP/1.1:引入了持久连接和管道化等功能,提升了性能。
- HTTP/2:改进了性能,支持多路复用和压缩头信息,减少了延迟。
- HTTP/3:基于QUIC协议,进一步减少延迟并提升性能。
请求(Request)与响应(Response)
理解 HTTP 中的请求与响应是掌握 Web 通信的基础。HTTP 请求和响应是客户端(如浏览器)与服务器之间交换信息的方式。以下是对 HTTP 请求和响应的详细理解:
Request
体系结构
HttpServletRequest
继承自 ServletRequest
接口。
ServletRequest -- 父接口
⬆️
HttpServletRequest -- 子接口
request 功能
获取请求行数据
请求行示例:GET /day02/demo1?name=zhangsan HTTP/1.1
1. 获取请求方式:GET
* String getMethod()
2. 获取虚拟目录:/day02
* String getContextPath()
3. 获取 Servlet 资源路径:/demo1
* String getServletPath()
4. 获取 GET 请求参数:name=zhangsan
* String getQueryString()
5. 获取请求 URI:/day02/demo1
* String getRequestURI()
* StringBuffer getRequestURL() // http://localhost/day02/demo1
6. 获取协议及版本:HTTP/1.1
* String getProtocol()
代码示例:
System.out.println(req.getMethod()); // GET/POST
System.out.println(req.getContextPath()); // /day02
System.out.println(req.getServletPath()); // /demo1
System.out.println(req.getQueryString()); // name=zhangsan
System.out.println(req.getRequestURI()); // /day02/demo1
System.out.println(req.getRequestURL()); // http://localhost:8080/day02/demo1
System.out.println(req.getProtocol()); // HTTP/1.1
获取请求头数据
方法:
String getHeader(String name)
:获取请求头的值Enumeration<String> getHeaderNames()
:获取所有请求头名称
代码示例:
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
System.out.println(name + "-----" + value);
}
获取浏览器信息:
String agent = req.getHeader("user-agent");
if (agent.contains("Chrome")) {
System.out.println("谷歌浏览器");
} else if (agent.contains("Firefox")) {
System.out.println("火狐浏览器");
}
获取请求体数据
请求体仅在 POST 请求中存在。
步骤:
- 获取流对象:
BufferedReader getReader()
:获取字符输入流
代码示例:
HTML 表单:
<form action="/requestDemo04" method="post">
<input name="username" placeholder="输入用户名"><br>
<input name="password" placeholder="输入密码"><br>
<input type="submit" value="注册">
</form>
Servlet 代码:
@WebServlet("/requestDemo04")
public class RequestDemo04 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
}
获取请求参数
通用方法:
String getParameter(String name)
:获取参数值String[] getParameterValues(String name)
:获取参数值的数组
注意:
- 对于 POST 请求,设置编码为 UTF-8 以避免中文乱码:
request.setCharacterEncoding("utf-8");
代码示例:
HTML 表单:
<form action="/Day02/requestDemo05" method="post">
<input name="username" placeholder="输入用户名"><br>
<input name="password" placeholder="输入密码"><br>
<input type="checkbox" name="hobby" value="game">游戏
<input type="checkbox" name="hobby" value="study">学习
<input type="submit" value="注册">
</form>
Servlet 代码:
@WebServlet("/requestDemo05")
public class RequestDemo05 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println("请求参数:" + username);
String[] hobbies = request.getParameterValues("hobby");
for (String hobby : hobbies) {
System.out.println(hobby);
}
}
}
请求转发
服务器内部的资源跳转。
步骤:
- 获取请求转发器对象:
RequestDispatcher getRequestDispatcher(String path)
- 使用
RequestDispatcher
对象进行转发:forward(ServletRequest request, ServletResponse response)
代码示例:
@WebServlet("/requestDemo06")
public class RequestDemo06 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestDispatcher dis = request.getRequestDispatcher("/request2");
dis.forward(request, response);
}
}
共享数据
- request 域:请求范围内的数据共享。
void setAttribute(String name, Object obj)
:存储数据Object getAttribute(String name)
:获取数据void removeAttribute(String name)
:移除数据
代码示例:
Servlet 1:
@WebServlet("/requestDemo08")
public class RequestDemo08 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("msg", "我是RequestDemo08的资源");
RequestDispatcher dis = request.getRequestDispatcher("/requestDemo09");
dis.forward(request, response);
}
}
Servlet 2:
@WebServlet("/requestDemo09")
public class RequestDemo09 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Object msg = request.getAttribute("msg");
System.out.println("我访问到的资源是:" + msg);
}
}
获取 ServletContext
ServletContext
是一个全局存储空间,所有用户都可以访问。
方法:
ServletContext servletContext = this.getServletContext();
servletContext.setAttribute("name", "zhangsan");
代码示例:
Servlet 1:
@WebServlet("/request1")
public class Request1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = request.getServletContext();
sc.setAttribute("msg", "hello1");
request.getRequestDispatcher("/request2").forward(request, response);
}
}
Servlet 2:
@WebServlet("/request2")
public class Request2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
ServletContext sc = request.getServletContext();
System.out.println("msg = " + sc.getAttribute("msg"));
}
}
Response
响应消息
-
响应行:包括协议/版本、响应状态码、状态码描述
- 例如:
HTTP/1.1 200 OK
- 例如:
-
响应头:
- 格式:
头名称: 值
- 示例:
Content-Type: text/html;charset=UTF-8
- 格式:
-
响应空行
-
响应体:传输给客户端的数据
响应体示例:
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Thu, 17 Sep 2020 02:59:05 GMT
Location: /servletB
我是response
重定向
- 重定向:资源跳转的方式
- 设置状态码为 302
- 设置响应头
Location
代码示例:
@WebServlet("/responseServlet01")
public class ResponseServlet01 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.sendRedirect("/Day03/responseServlet02");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
@WebServlet("/responseServlet02")
public class ResponseServlet02 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("responseServlet02");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doPost(request, response);
}
}
forward
和 redirect
区别
-
重定向 (
redirect
):- 地址栏发生变化
- 可以访问其它站点资源
- 两次请求,不能使用 request 对象共享数据
-
转发 (
forward
):- 地址栏路径不变
- 只能访问当前服务器资源
- 一次请求,可以使用 request 对象共享数据
注意: 不能使用重定向来访问 request
域中的数据。