一.基本概念
1.1 C/S架构基本概念
C/S架构(Client/Server,客户端/服务器模式),是一种比较早的软件体系结构,也是生活中很常 见的结构。这种结构将需要处理的业务合理地分配到客户端和服务器端,客户端通常负责完成与用 户的交互任务,服务器通常负责数据的管理。
C/S架构的主要优点如下:
- 客户端的界面和功能可以很丰富。
- 应用服务器的负荷较轻。
- 响应速度较快。
C/S架构的主要缺点如下:
- 适用面窄,用户群固定。
- 维护和升级的成本高,所有的客户端都需要更新版本。
1.2 B/S架构基本概念
B/S架构(Browser/Server,浏览器/服务器模式),是互联网兴起后的软件体系结构,该结构将 系统功能实现的主要业务逻辑集中到服务器端,极少数业务逻辑在浏览器实现,浏览器通常负责完 成与用户的交互任务,服务器通常负责数据的管理。 B/S架构的主要优点如下:
- 无需安装客户端,只要有浏览器即可。
- 适用面广,用户群不固定。
- 通过权限控制实现多客户访问的目的,交互性较强。
- 维护和升级的成本低,无需更新所有客户端版本。
B/S架构的主要缺点如下:
- 应用服务器的负荷较重。
- 浏览器的界面和功能想要达到客户端的丰富程度需要花费大量的成本。
- 在跨浏览器上不尽如人意,适配比较麻烦。
1.3 JavaWeb基本概念
Web本意为网页的含义,这里表示互联网上供外界访问的资源。
互联网上供外界访问的资源主要分为以下两种:
- 静态资源:主要指Web页面中供人们浏览的数据始终是不变。
- 动态资源:主要指Web页面中供人们浏览的数据由程序产生,不同时间点访问页面看到的内容各不相同。
JavaWeb主要指使用Java语言进行动态Web资源开发技术的统称,是解决相关Web互联网领域的技术总和。
早期B/S架构(服务器放静态资源)
后来的B/S架构(服务器放动态资源)
二.Tomcat服务器
Tomcat本意为公猫的含义,最初是由Sun公司的软件架构师詹姆斯·邓肯·戴维森开发的,后来他帮 助将其变为开源项目并由Sun公司贡献给Apache软件基金会。
Tomcat 服务器是一个开源的轻量级
2.1 目录结构
2.2 启动和关闭
2.3 修改配置文件
server.xml设置端口号、设置域名或IP、默认加载的项目、请求 编码等。
tomcat-users.xml文件用来配置管理Tomcat服务器的用户与权限
三.Servlet的概念和使用
3.1 Servlet的基本概念
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,是Java语言编写 的服务器端程序,换句话说,Servlet就是运行在服务器上的Java类。
Servlet用来完成B/S架构下客户端请求的响应处理,也就是交互式地浏览和生成数据,生成动态 Web内容。
3.2 Servlet的编程步骤
- 建立一个Java Web Application项目并配置Tomcat服务器。
- 自定义类实现Servlet接口或继承 HttpServlet类(推荐) 并重写service方法。
- 将自定义类的信息配置到 web.xml文件并启动项目,配置方式如下:
在浏览器上访问的方式为:
http ://localhost:8080/工程路径/url-pattern的内容
package com.example.task01_demo02;
import jakarta.servlet.*;
import java.io.IOException;
public class HelloServlet2 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 "";
}
@Override
public void destroy() {
}
}
3.3 Servlet程序的第二种编写方式
GenericServlet类
javax.servlet.GenericServlet类主要用于定义一个通用的、与协议无关的servlet,该类实现了 Servlet接口。
若编写通用servlet,只需重写service抽象方法即可。
public class eeee extends GenericServlet{
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("继承GenericServlet的方式创建Servlet");
}
}
3.4 Servlet程序的第三种编写方式
HttpServlet类
javax.servlet.http.HttpServlet类是个抽象类并继承了GenericServlet类。 用于创建适用于网站的HTTP Servlet,该类的子类必须至少重写一个方法。
public class HelloServlet3 extends HttpServlet {
public HelloServlet3() {
System.out.println("构造方法调用了");
}
@Override
public void destroy() {
System.out.println("销毁操作开始!");
}
@Override
public void init() throws ServletException {
System.out.println("初始化操作开始!");
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("采用继承HttpServlet类的方式创建,以后的开发中推荐该方式");
}
}
四.Servlet的生命周期(**)
五. POST和GET请求(**)
5.1 GET请求与POST请求
GET请求
POST请求
5.2 ServletRequest接口
javax.servlet.ServletRequest接口主要用于向servlet提供客户端请求信息,可以从中获取到任何 请求信息。
Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法
Map<String,String[]> parameterMap = req.getParameterMap();
Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
for (Map.Entry<String, String[]> me : entries) {
System.out.println(me.getKey()+"对应到的数值有:");
for (String ts : me.getValue()) {
System.out.println(ts + "");
5.3 HttpServletRequest接口
javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP 请求信息的功能。
不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置。
可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据。
5.4 ServletResponse接口
javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应。
Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法。
常用方法:
System.out.println("发送请求的客户端IP地址为:"+req.getRemoteAddr());
System.out.println("发送请求的客户端端口号为:"+req.getRemotePort());
System.out.println("请求资源的路径为:"+req.getRequestURI());
System.out.println("请求资源的完整路径为:"+req.getRequestURI());
System.out.println("请求方式为:"+req.getMethod());
System.out.println("请求的附带参数为:"+req.getQueryString());
System.out.println("请求的Servlet路径为:"+req.getServletPath());
5.5 ServletResponse接口
javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应。
Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法。
//5.向浏览器发出响应数据
// 获取相应数据到的默认编码方式
String characterEncoding = resp.getCharacterEncoding();
System.out.println("服务器响应数据的默认编码方式:"+characterEncoding);//ISO-8859-1
//设置服务器和浏览器的编码方式以及文本类型
resp.setContentType("text/html;charest = UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("I Received!");
System.out.println("服务器发送数据成功");
writer.close();
六.Servlet接收中文乱码
6.1 接收乱码原因
javax.servlet.ServletConfig接口用于描述Servlet本身的相关配置信息,在初始化期间用于将信息 传递给Servlet配置对象。
解决POST接收乱码
解决GET接收乱码
七.Servlet+JDBC应用
以下代码是实现获取请求对象的信息并打包交给DAO层最后将处理结果响应到浏览器:
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取请求对象中保存的用户名和密码信息
String userName = request.getParameter("userName");
System.out.println("获取到的用户名为:" + userName);
String password = request.getParameter("password");
System.out.println("获取到的密码为:" + password);
// 2.将接受到的用户名和密码信息打包成用户对象交给DAO层进行处理
User user = new User(userName, password);
UserDao userDao = new UserDao();
int res = userDao.createUser(user);
// 3.将处理结果响应到浏览器
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
if (1 == res) {
System.out.println("注册成功!");
writer.write("<h1>注册成功!</h1>");
} else {
writer.write("<h1>注册失败!</h1>");
}
writer.close();
}
实现与数据库的连接(传输数据):
public int createUser(User user) {
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
// 1.获取连接
connection = DbUtil.getConnection();
// 2.准备sql语句
String sql = "insert into t_user values(null, ?, ?)";
// 3.获取PrepareStatement类型的引用
preparedStatement = connection.prepareStatement(sql);
// 4.向问号所占的位置设置数据
preparedStatement.setString(1, user.getUserName());
preparedStatement.setString(2, user.getPassword());
// 5.执行sql语句
int row = preparedStatement.executeUpdate();
return row; // 执行成功
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 6.关闭资源
try {
DbUtil.closeConnection(connection, preparedStatement);
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0; // 执行失败
}
}
八.重定向和转发
1.1 重定向的概念
首先客户浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客 户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location 地址,服务器根据此请求寻找资源并发送给客户
1.2 重定向的实现:
重定向即给浏览器发送一个新的位置:
public class RedirectServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("接收到了浏览器的请求...");
// 重定向,也就是给浏览器发送一个新的位置
response.sendRedirect("target.html");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
1.3 重定向的原理(总共请求了两次):
1.4 重定向的特点
- 重定向之后,浏览器地址栏的URL会发生改变。
- 重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象。
- 重定向的URL可以是其它项目工程。(
response.sendRedirect("https://www.baidu.com/index.php?tn=monline_3_dg");)```
```
九.转发
1.1 转发的概念
一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续处理,转发 的各个组件会共享Request和Response对象。 也就是让Web组件将任务转交给了另一个Web组件
1.2 转发的实现
public class ForwardServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("接收到了浏览器的请求...");
// 向request对象中设置属性信息
request.setAttribute("key1", "value1");
// 转发,也就是让Web组件将任务转交给另外一个Web组件
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/targetServlet");
1.3 转发的特点
- 转发之后浏览器地址栏的URL不会发生改变。
- 转发过程中共享Request对象。
- 转发的URL不可以是其它项目工程。
共享Request对象的测试:
// 获取request对象中的属性值判断是否共享
Object key1 = request.getAttribute("key1");
System.out.println("获取到的属性值为:" + key1); // value1
1.4 重定向和转发的比较
十.Servlet线程安全
服务器在收到请求之后,会启动一个线程来进行相应的请求处理。
默认情况下,服务器为每个Servlet只创建一个对象实例。当多个请求访问同一个Servlet时,会有 多个线程访问同一个Servlet对象,此时就可能发生线程安全问题。
多线程并发逻辑,需要使用synchronized对代码加锁处理,但尽量避免使用。
解决方法(使用synchronized对代码加锁处理,但性能会下降):
synchronized (this) {
// 1.获取request对象中名字为name的参数数值并赋值给成员变量name
String name = request.getParameter("name");
System.out.println("获取到的name数值为:" + name);
// 2.睡眠5秒钟
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 3.使用打印流将成员变量name的数值发送给浏览器
PrintWriter writer = response.getWriter();
writer.write("<h1>" + name + "</h1>");
writer.close();
//}
十一.状态管理
Web程序基于HTTP协议通信,而HTTP协议是”无状态”的协议,一旦服务器响应完客户的请求之 后,就断开连接,而同一个客户的下一次请求又会重新建立网络连接。
服务器程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品。因此,有必 要跟踪同一个客户发出的一系列请求。
把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理。
多次交互的数据状态可以在客户端保存,也可以在服务器端保存。状态管理主要分为以下两类:
客户端管理:将状态保存在客户端。基于Cookie技术实现。
服务器管理:将状态保存在服务器端。基于Session技术实现。
十二.cookie
12.1 cookie的概念
Cookie本意为”饼干“的含义,在这里表示客户端以“名-值”形式进行保存的一种技术。
浏览器向服务器发送请求时,服务器将数据以Set-Cookie消息头的方式响应给浏览器,然后浏览器 会将这些数据以文本文件的方式保存起来。 当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器。-
12.2 cookie的创建与修改
方法:
创建和添加:
public class CookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.测试一下浏览器的请求是否到达
System.out.println("看看有没有执行到这里哦!");
// 2.创建Cookie对象并添加到响应信息中
Cookie cookie = new Cookie("name", "zhangfei");
response.addCookie(cookie);
System.out.println("创建Cookie成功!");
}
获取和修改:
@WebServlet(name = "CookieServlet2", urlPatterns = "/cookie2")
public class CookieServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取客户端发来的Cookie信息并打印出来
Cookie[] cookies = request.getCookies();
System.out.println("获取到的Cookie信息有:");
for (Cookie tc : cookies) {
System.out.println(tc.getName() + "对应的值为:" + tc.getValue());
}
}
public class CookieServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取客户端发来的Cookie信息并打印出来
Cookie[] cookies = request.getCookies();
for (Cookie tc : cookies) {
// 2.当获取到的Cookie对象的名字为name时,将对应的数值修改为guanyu并添加到响应信息中
if ("name".equalsIgnoreCase(tc.getName())) {
tc.setValue("guanyu");
response.addCookie(tc);
break;
}
}
System.out.println("修改Cookie信息成功!");
}
12.3 cookie的生命周期(有效范围):
默认情况下,浏览器会将Cookie信息保存在内存中,只要浏览器关闭,Cookie信息就会消失。
如果希望关闭浏览器后Cookie信息仍有效,可以通过Cookie类的成员方法实现。
先获取cookie的使用期限 然后再修改使用期限 之后添加到响应信息中:
@WebServlet(name = "CookieServlet4", urlPatterns = "/cookie4")
public class CookieServlet4 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie信息
Cookie cookie = new Cookie("name", "liubei");
// 2.获取Cookie信息的默认使用期限
int maxAge = cookie.getMaxAge();
System.out.println("该Cookie的默认使用期限是:" + maxAge);
// 3.修改Cookie信息的使用期限
// 正数表示在指定的秒数后失效 负数表示浏览器关闭后失效 0表示马上失效
//cookie.setMaxAge(0);
cookie.setMaxAge(60*10);
// 4.添加到响应信息中
response.addCookie(cookie);
System.out.println("设置Cookie的生命周期成功!");
}
12.4 cookie的路径
修改路径:
public class CookieServlet5 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.创建Cookie对象并指定数值
//Cookie cookie = new Cookie("name", "zhaoyun");
Cookie cookie = new Cookie("name", "huangzhong");
// 3.修改Cookie的路径信息
cookie.setPath(request.getContextPath() + "/hello");
// 2.添加到响应信息中
response.addCookie(cookie);
System.out.println("设置Cookie路径成功!");
}
十三.session
13.1 session基本概念
cookie保存在客户端 session保存服务端
Session本意为"会话"的含义,是用来维护一个客户端和服务器关联的一种技术。
浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一 个Session对象,该对象有一个id属性且该值唯一,我们称为SessionId,并且服务器会将这个 SessionId以Cookie方式发送给浏览器存储。
浏览器再次访问服务器时会将SessionId发送给服务器,服务器可以依据SessionId查找相对应的 Session对象
13.2 获取与修改session
创建session对象并判断是否为新创建的session对象以及获取session的编号:
public class SessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.调用getSession方法获取或者创建Session对象
HttpSession session = request.getSession();
// 2.判断该Session对象是否为新建的对象
System.out.println(session.isNew()? "新创建的Session对象": "已有的Session对象");
// 3.获取编号并打印
String id = session.getId();
System.out.println("获取到的Session编号为:" + id);
}
设置session的属性以及删除:
public class SessionServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
// 1.设置属性名和属性值
session.setAttribute("name", "machao");
// 2.获取指定属性名对应的属性值
System.out.println("获取到的属性值为:" + session.getAttribute("name")); // machao
// 3.删除指定的属性名
session.removeAttribute("name");
// 4.获取指定属性名对应的属性值
System.out.println("获取到的属性值为:" + session.getAttribute("name")); // null
}
13.3 session的生命周期(有效范围)
为了节省服务器内存空间资源,服务器会将空闲时间过长的Session对象自动清除掉,服务器默认 的超时限制一般是30分钟。
使用HttpSession接口的成员方法实现失效实现的获取和设置。
创建session对象并获取session对象的有效时间然后进行修改:
public class SessionServlet3 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.获取Session对象
HttpSession session = request.getSession();
// 2.获取对象的默认失效时间并打印
int maxInactiveInterval = session.getMaxInactiveInterval();
System.out.println("获取到的失效时间为:" + maxInactiveInterval); // 1800
// 3.修改实现时间后重新获取并打印
session.setMaxInactiveInterval(1200);
maxInactiveInterval = session.getMaxInactiveInterval();
System.out.println("获取到的失效时间为:" + maxInactiveInterval); // 1200
}
修改session有效时间还可以通过修改配置文件
13.4 Session的特点
数据比较安全。
能够保存的数据类型丰富,而Cookie只能保存字符串。
能够保存更多的数据,而Cookie大约保存4KB。
数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务 器的性能