一.基本概念
1.C/S架构的概念
● C/S架构(Client/Server,客户端/服务器模式),是一种比较早的软件体系结构,也是生活中很常见的结构。这种结构将需要处理的业务合理地分配到客户端和服务器端,客户端通常负责完成与用户的交互任务,服务器通常负责数据的管理。 ● C/S架构的主要优点如下: 客户端的界面和功能可以很丰富。 应用服务器的负荷较轻。 响应速度较快。 ● C/S架构的主要缺点如下: 适用面窄,用户群固定。 维护和升级的成本高,所有的客户端都需要更新版本。
2.B/S架构的概念
● B/S架构(Browser/Server,浏览器/服务器模式),是互联网兴起后的软件体系结构,该结构将系统功能实现的主要业务逻辑集中到服务器端,极少数业务逻辑在浏览器实现,浏览器通常负责完成与用户的交互任务,服务器通常负责数据的管理。 ● B/S架构的主要优点如下: 无需安装客户端,只要有浏览器即可。 适用面广,用户群不固定。 通过权限控制实现多客户访问的目的,交互性较强。 维护和升级的成本低,无需更新所有客户端版本。 ● B/S架构的主要缺点如下: 应用服务器的负荷较重。 浏览器的界面和功能想要达到客户端的丰富程度需要花费大量的成本。 在跨浏览器上不尽如人意,适配比较麻烦。
3.JavaWeb的概念
● Web本意为网页的含义,这里表示互联网上供外界访问的资源。 ● 互联网上供外界访问的资源主要分为以下两种: 静态资源:主要指Web页面中供人们浏览的数据始终是不变。 动态资源:主要指Web页面中供人们浏览的数据由程序产生,不同时间点 访问页面看到的内容各不相同。 ● JavaWeb主要指使用Java语言进行动态Web资源开发技术的统称,是解决相关Web互联网领域的技术总和。
● 早期的B/S架构 ● 后来的B/S架构
二.HTTP协议
1.HTTP协议的概念
● HTTP协议(HyperText Transfer Protocol,超文本传输协议)是由W3C(万维网联盟)组织制定的一种应用层协议,是用来规范浏览器与Web服务器之间如何通讯的数据格式,主要涉及浏览器的发请求格式和服务器的响应格式。 ● HTTP协议通常承载于TCP协议之上,而承载于TLS或SSL协议层之上的协议就是常说的HTTPS协议。 ● HTTP默认的端口号为80,HTTPS默认的端口号为443。
2.HTTP请求格式
客户端发送一个HTTP请求到服务器的请求消息主要包括:请求行、请求头、空白行和请求体。
请求行用来说明请求类型和要访问的资源以及所使用的HTTP版本,格式如下: 请求类型 请求的路径 协议的版本(1.1) 请求头是紧接着请求行(即第一行)之后的部分,用来说明服务器要使用的附加信息,格式 (key:value)如下: 主机 请求长度 请求的浏览器相关信息 空白行就是请求头部的空行,即使后面的请求数据为空则必须有空行。 请求体也叫请求数据,可以添加任意的其他数据。
比如:
3.HTTP响应格式
通常情况下服务器接收并处理客户端发过来的请求后会返回一个HTTP的响应消息,主要包括:响应行、响应头、空白行和响应体。
响应行用来说明HTTP协议版本号和状态码以及状态消息,格式如下: 协议的版本(1.0 1.1) 状态码 (200 成功 404 路径错误 500 服务错误) 状态信息 响应头用来说明客户端要使用的一些附加信息,格式(key:value)。 空白行就是响应头部的空行,即使后面的请求数据为空则必须有空行。 响应体用来服务器返回给客户端的文本信息。
三.Tomcat服务器
1.基本概念
● Tomcat本意为公猫的含义,最初是由Sun公司的软件架构师詹姆斯·邓肯·戴维森开发的,后来他帮助将其变为开源项目并由Sun公司贡献给Apache软件基金会。 ● Tomcat 服务器是一个开源的轻量级Web应用服务器,在中小型系统和并发量小的场合下被普遍使用,是开发和调试Servlet、JSP 程序的首选。
2.安装地址
tomcat 地址: http://tomcat.apache.org/
3.目录结构
● bin 主要存放二进制可执行文件和脚本。 ● conf 主要存放各种配置文件。 ● lib 主要用来存放Tomcat运行需要加载的jar包。 ● logs 主要存放Tomcat在运行过程中产生的日志文件。 ● temp 主要存放Tomcat在运行过程中产生的临时文件。 ● webapps 主要存放应用程序,当Tomcat启动时会去加载该目录下的应用程序。 ● work 主要存放tomcat在运行时的编译后文件,例如JSP编译后的文件。
4.启动和关闭
● 启动方式 使用bin目录下的批处理文件startup.bat来启动Tomcat服务器,若出现一个毫秒数说明启动成功。 ● 关闭方式 使用bin目录下的批处理文件shutdown.bat来关闭Tomcat服务器。 ● 注意事项 启动之前首先安装JDK并配置环境变量JAVA_HOME,若希望Tomcat服务器可以在任意路径启动,则需要配置环境变量CATALINA_HOME。 启动信息乱码的处理方式:logging.properties文件修改为 java.util.logging.ConsoleHandler.encoding = GBK
5.配置文件
● server.xml文件是服务器的主配置文件,可以设置端口号、设置域名或IP、默认加载的项目、请求编码等。
<Connector port="8888" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
● tomcat-users.xml文件用来配置管理Tomcat服务器的用户与权限 。
<role rolename="manager-gui"/>
<user username="admin" password="123456" roles="manager-gui"/>
四.Servlet的概念和使用
1.基本概念
● Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,是Java语言编写的服务器端程序,换句话说,Servlet就是运行在服务器上的Java类。 ● Servlet用来完成B/S架构下客户端请求的响应处理,也就是交互式地浏览和生成数据,生成动态Web内容。
2.Servlet的编程步骤
● 建立一个Java Web Application项目并配置Tomcat服务器。 ● 自定义类实现Servlet接口或继承 HttpServlet类(推荐) 并重写service方法。 ● 将自定义类的信息配置到 web.xml文件并启动项目,配置方式如下:
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.javaweb.demo01.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
● 在浏览器上访问的方式为:
http://localhost:8080/工程路径/url-pattern的内容
3.Servlet接口
①基本概念
javax.servlet.Servlet接口用于定义所有servlet必须实现的方法。
②常用的方法
4.GenericServlet类
①基本概念
● javax.servlet.GenericServlet类主要用于定义一个通用的、与协议无关的servlet,该类实现了Servlet接口。 ● 若编写通用servlet,只需重写service抽象方法即可。
②常用的方法
5.HttpServlet类
①基本概念
javax.servlet.http.HttpServlet类是个抽象类并继承了GenericServlet类。 用于创建适用于网站的HTTP Servlet,该类的子类必须至少重写一个方法。
②常用的方法
6.Servlet 的生命周期
public class HelloServlet extends HttpServlet {
public HelloServlet() {
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("初始化操作开始。。。");
}
}
输出结果: 构造方法被调用 初始化操作开始。。。 继承HttpServlet方式 刷新页面后 继承HttpServlet方式 继承HttpServlet方式 继承HttpServlet方式 停止访问后 销毁操作开始。。。
● 构造方法只被调用一次,当第一次请求Servlet时调用构造方法来创建Servlet的实例. ● init方法只被调用一次,当创建好Servlet实例后立即调用该方法实现Servlet的初始化。 ● service方法被多次调用,每当有请求时都会调用service方法来用于请求的响应。 ● destroy方法只被调用一次,当该Servlet实例所在的Web应用被卸载前调用该方法来释放当前占用的资源。
五. POST和GET请求
1.GET请求
发出GET请求的主要方式: (1)在浏览器输入URL按回车 (2)点击< a >超链接 (3)点击submit按钮,提交 表单 GET请求特点: 会将请求数据添加到请求URL地址的后面,只能提交少量的数据、不安全
2.POST请求
发出POST请求的方法如下: 点击submit按钮,提交 表单 POST请求的特点: 请求数据添加到HTTP协议体中,可提交大量数据、安全性好
3.ServletRequest接口
①基本概念
● javax.servlet.ServletRequest接口主要用于向servlet提供客户端请求信息,可以从中获取到任何请求信息。 ● Servlet容器创建一个ServletRequest对象,并将其作为参数传递给Servlet的service方法。
②常用方法
4.HttpServletRequest接口
①基本概念
● javax.servlet.http.HttpServletRequest接口是ServletRequest接口的子接口,主要用于提供HTTP请求信息的功能。 ● 不同于表单数据,在发送HTTP请求时,HTTP请求头直接由浏览器设置。 ● 可直接通过HttpServletRequest对象提供的一系列get方法获取请求头数据。
②常用方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>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>
<?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-name>ParameterServlet</servlet-name>
<servlet-class>com.Servlet.demo01.ParameterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ParameterServlet</servlet-name>
<url-pattern>/parameter</url-pattern>
</servlet-mapping>
</web-app>
public class ParameterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
System.out.println("获取到的姓名" + name);
String[] hobbies = request.getParameterValues("hobby");
for (String ts:hobbies) {
System.out.print(ts + " ");
}
System.out.println();
System.out.println("=========================");
Enumeration<String> parameterNames = request.getParameterNames();
System.out.println("获取到的所有参数名称为");
while (parameterNames.hasMoreElements()){
System.out.print(parameterNames.nextElement() +" ");
}
System.out.println();
System.out.println("=========================");
Map<String, String[]> map = request.getParameterMap();
Set<Map.Entry<String, String[]>> entries = map.entrySet();
for (Map.Entry<String, String[]> me:entries) {
System.out.print(me.getKey() + "对应的值:");
for (String s:me.getValue()) {
System.out.print(s + " ");
}
System.out.println();
}
System.out.println("=========================");
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());
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
5.ServletResponse接口
①基本概念
● javax.servlet.ServletResponse接口用于定义一个对象来帮助Servlet向客户端发送响应。 ● Servlet容器创建ServletResponse对象,并将其作为参数传递给servlet的service方法。
②常用方法
6.HttpServletResponse接口
①基本概念
● javax.servlet.http.HttpServletResponse接口继承ServletResponse接口,以便在发送响应时提供特定于HTTP的功能。
②常用方法
public class HelloWorld extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponseresponse)throws IOException, ServletException {
response.setContentType(“text/html;charset=utf-8”);
PrintWriter out= response.getWriter();
out.println(“<html><body> Hello world!</body></html>”);
out.close();
}
}
六.Servlet接收中文乱码
1.接收乱码原因
● 浏览器在提交表单时,会对中文参数值进行自动编码。当Tomcat服务器接收到浏览器请求后自动解码,当编码与解码方式不一致时,就会导致乱码。
2.解决POST接收乱码
接收之前设置编码方式:
request.setCharacterEncoding(“utf-8”)
提示:
必须在调用request.getParameter(“name”)之前设置
3.解决GET接收乱码
将接收到的中文乱码重新编码:
String name = request.getParameter("name");
String userName = new String(name.getBytes(“ISO-8859-1”),“utf-8");
七.ServletConfig接口
1.基本概念
● javax.servlet.ServletConfig接口用于描述Servlet本身的相关配置信息,在初始化期间用于将信息传递给Servlet配置对象。
2.配置方式
<servlet>
<servlet-name>servletconfig</servlet-name>
<servlet-class>com.Servlet.demo01.ServletConfig</servlet-class>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
3.常用方法
八.ServletContext接口
1.基本概念
● javax.servlet.ServletContext接口主要用于定义一组方法,Servlet使用这些方法与它的Servlet容器通信。 ● 服务器容器在启动时会为每个项目创建唯一的一个ServletContext对象,用于实现多个Servlet之间的信息共享和通信。 ● 在Servlet中通过this.getServletContext()方法可以获得ServletContext对象。
2.配置方式
<context-param>
<param-name>username</param-name>
<param-value>admin</param-value>
<context-param>
<context-param>
<param-name>password</param-name>
<param-value>123456</param-value>
<context-param>
3.常用方法
九.Servlet+JDBC应用
● 在Servlet中可以使用JDBC技术访问数据库,常见功能如下: 查询DB数据,然后生成显示页面,例如:列表显示功能。 接收请求参数,然后对DB操作,例如:注册、登录、修改密码等功能。 ● 为了方便重用和便于维护等目的,经常会采用DAO(Data Access Object)模式对数据库操作进行独立封装。 ● DAO工厂(工厂模式) 工厂类:封装了对象的创建细节,为调用者提供符合要求的对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<form action="register" method="post">
用户名:<input type="text" name="userName"/><br/>
密 码:<input type="text" name="password"/><br/>
<input type="submit" value="注册"/>
</form>
</body>
</html>
<?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-name>RegisterServlet</servlet-name>
<servlet-class>com.javaweb.demo01.servlet.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/register</url-pattern>
</servlet-mapping>
</web-app>
public class RegisterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userName = request.getParameter("userName");
System.out.println("获取到的用户名" + userName);
String password = request.getParameter("password");
System.out.println("获取到的密码" + password);
User user = new User(userName,password);
UserDao userDao = new UserDao();
int res = userDao.createUser(user);
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
if (1 == res){
System.out.println("注册成功");
writer.write("<h1>注册成功</h1>");
}else {
System.out.println("注册失败");
writer.write("<h1>注册失败</h1>");
}
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
public class User {
private int id;
private String userName;
private String password;
public User() {
}
public User(String userName, String password) {
this.userName = userName;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
public class DBUtil {
private static String jdbcName;
private static String dbUrl;
private static String dbUserName;
private static String dbPassword;
static {
jdbcName = "com.mysql.jdbc.Driver";
dbUrl = "jdbc:mysql://localhost:3306/db_web";
dbUserName = "admin";
dbPassword = "123456";
try {
Class.forName(jdbcName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws SQLException {
Connection con = DriverManager.getConnection(dbUrl,dbUserName,dbPassword);
return con;
}
public static void closeConnection(Connection con, PreparedStatement ps) throws SQLException {
if (null != con){
con.close();
}
if (null != ps){
ps.close();
}
}
}
public class UserDao {
public int createUser(User user){
Connection con = null;
PreparedStatement ps = null;
try {
con = DBUtil.getConnection();
String sql = "insert into t_user values(null,?,?)";
ps = con.prepareStatement(sql);
ps.setString(1,user.getUserName());
ps.setString(2,user.getPassword());
int row = ps.executeUpdate();
return row;
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
DBUtil.closeConnection(con,ps);
} catch (SQLException e) {
e.printStackTrace();
}
}
return 0;
}
}
十.重定向和转发
1.重定向的概述
①重定向的概念
首先客户浏览器发送http请求,当web服务器接受后发送302状态码响应及对应新的location给客户浏览器,客户浏览器发现是302响应,则自动再发送一个新的http请求,请求url是新的location地址,服务器根据此请求寻找资源并发送给客户。
②重定向的实现
实现重定向需要借助javax.servlet.http.HttpServletResponse接口中的以下方法:
③重定向的原理
④重定向的特点
● 重定向之后,浏览器地址栏的URL会发生改变。 ● 重定向过程中会将前面Request对象销毁,然后创建一个新的Request对象。 ● 重定向的URL可以是其它项目工程。
2.转发的概述
①转发的概念
一个Web组件(Servlet/JSP)将未完成的处理通过容器转交给另外一个Web组件继续处理,转发的各个组件会共享Request和Response对象。
②转发的实现
● 绑定数据到Request对象 ● 获取转发器对象 ● 转发操作
③转发的特点
- 转发之后浏览器地址栏的URL不会发生改变。
- 转发过程中共享Request对象。
- 转发的URL不可以是其它项目工程。
④重定向和转发的比较
十一.Servlet线程安全
● 服务器在收到请求之后,会启动一个线程来进行相应的请求处理。 ● 默认情况下,服务器为每个Servlet只创建一个对象实例。当多个请求访问同一个Servlet时,会有多个线程访问同一个Servlet对象,此时就可能发生线程安全问题。 ● 多线程并发逻辑,需要使用synchronized对代码加锁处理,但尽量避免使用。
@WebServlet(name = "ThreadServlet",urlPatterns = "/thread")
public class ThreadServlet extends HttpServlet {
private String name;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
synchronized (this) {
name = request.getParameter("name");
System.out.println("获取到的name为" + name);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
PrintWriter writer = response.getWriter();
writer.write("<h1>" + name + "</h1>");
writer.close();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doPost(request, response);
}
}
十二.状态管理
● Web程序基于HTTP协议通信,而HTTP协议是”无状态”的协议,一旦服务器响应完客户的请求之后,就断开连接,而同一个客户的下一次请求又会重新建立网络连接。 ● 服务器程序有时是需要判断是否为同一个客户发出的请求,比如客户的多次选购商品。因此,有必要跟踪同一个客户发出的一系列请求。 ● 把浏览器与服务器之间多次交互作为一个整体,将多次交互所涉及的数据保存下来,即状态管理。 ● 多次交互的数据状态可以在客户端保存,也可以在服务器端保存。状态管理主要分为以下两类: 客户端管理:将状态保存在客户端。基于Cookie技术实现。 服务器管理:将状态保存在服务器端。基于Session技术实现。
13.Cookie技术
1.基本概念
● Cookie本意为”饼干“的含义,在这里表示客户端以“名-值”形式进行保存的一种技术。 ● 浏览器向服务器发送请求时,服务器将数据以Set-Cookie消息头的方式响应给浏览器,然后浏览器会将这些数据以文本文件的方式保存起来。 ● 当浏览器再次访问服务器时,会将这些数据以Cookie消息头的方式发送给服务器。
2.相关方法
● 使用javax.servlet.http.Cookie类的构造方法实现Cookie的创建。 ● 使用javax.servlet.http.HttpServletResponse接口的成员方法实现Cookie的添加。 ● 使用javax.servlet.http.HttpServletRequest接口的成员方法实现Cookie对象的获取。 ● 使用javax.servlet.http.Cookie类的构造方法实现Cookie对象中属性的获取和修改。
3.Cookie的生命周期
● 默认情况下,浏览器会将Cookie信息保存在内存中,只要浏览器关闭,Cookie信息就会消失。 ● 如果希望关闭浏览器后Cookie信息仍有效,可以通过Cookie类的成员方法实现。
4.Cookie的路径问题
● 浏览器在访问服务器时,会比较Cookie的路径与请求路径是否匹配,只有匹配的Cookie才会发送给服务器。 ● Cookie的默认路径等于添加这个Cookie信息时的组件路径,例如:/项目名/目录/add.do请求添加了一个Cookie信息,则该Cookie的路径是 /项目名/目录。 ● 访问的请求地址必须符合Cookie的路径或者其子路径时,浏览器才会发送Cookie信息。
5.Cookie的特点
Cookie技术不适合存储所有数据,程序员只用于存储少量、非敏感信息,原因如下:
- 将状态数据保存在浏览器端,不安全。
- 保存数据量有限制,大约4KB左右。
- 只能保存字符串信息。
- 可以通过浏览器设置为禁止使用。
14.Session技术
1.基本概念
● Session本意为"会话"的含义,是用来维护一个客户端和服务器关联的一种技术。 ● 浏览器访问服务器时,服务器会为每一个浏览器都在服务器端的内存中分配一个空间,用于创建一个Session对象,该对象有一个id属性且该值唯一,我们称为SessionId,并且服务器会将这个SessionId以Cookie方式发送给浏览器存储。 ● 浏览器再次访问服务器时会将SessionId发送给服务器,服务器可以依据SessionId查找相对应的Session对象
2.相关方法
● 使用javax.servlet.http.HttpServletRequest接口的成员方法实现Session的获取。 ● 使用javax.servlet.http.HttpSession接口的成员方法实现判断和获取。 ● 使用javax.servlet.http.HttpSession接口的成员方法实现属性的管理。
3.Session的生命周期
● 为了节省服务器内存空间资源,服务器会将空闲时间过长的Session对象自动清除掉,服务器默认的超时限制一般是30分钟。
● 使用javax.servlet.http.HttpSession接口的成员方法实现失效实现的获取和设置。 ● 可以配置web.xml文件修改失效时间。
<session-config>
<session-timeout>30</session-timeout>
</session-config>
4.Session的特点
● 数据比较安全。 ● 能够保存的数据类型丰富,而Cookie只能保存字符串。 ● 能够保存更多的数据,而Cookie大约保存4KB。 ● 数据保存在服务器端会占用服务器的内存空间,如果存储信息过多、用户量过大,会严重影响服务器的性能。
|