# javaServletWebAppPro
**Repository Path**: javafdx/java-servlet-web-app-pro
## Basic Information
- **Project Name**: javaServletWebAppPro
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-05-27
- **Last Updated**: 2024-06-22
## Categories & Tags
**Categories**: Uncategorized
**Tags**: javaServlet
## README
# javaServletWebAppPr
1. 目前环境库只有jdk包,没有servlet包
将servlet包,引入idea
File-->Project Stru-->Module-->Depend-->加号,找到需要加入的jar包servlet-api.jar
servlet包在tomcat安装包lib文件夹下
implements Servlet 实现这个接口,快捷键ctrl+i 实现servlet五个方法
2. 在WEB-INF目录下新建一个子目录:lib(这个目录名可不能随意,必须全部小写lib),并且将链接数据库的驱动
jar包放到lib目录下。
3. 在web.xml文件中共完成StudentServlet类的注册(请求路劲和servlet之间对应起来)
4. 让IDEA工具去关联Tomcat服务器,关联的过程当中将webapp部署到Tomcat服务器当中。
idea工具右上角,绿色小锤子右边有一个:Add Configuration
左上角加号,点击Tomcat Server-->local
在弹出的界面中设置服务器Server的参数(基本不用动)
在当前窗口中有一个Deployment(点击这个用来部署webapp),继续点击加号,部署即可。
(往下滑)修改Application context为: /xmm
访问:http://localhost:8080/xmm/student.html
### 环境不一样,要重新加载servlet-api.jar
### servlet生命周期
1. Servlet对象的创建,对象上方法的调用,对象最终的销毁,javaweb程序员时无权干涉的
2. Servlet对象的生命周期是由tomcat服务器(webserver)全权负责
3. Tomcat服务器通常称为Web容器
4. 思考:我们自己new的servlet对象受web容器的管理吗?
我们自己new的servlet对象时不受Web容器管理的;
web容器创建的servlet对象,这些servlet对象都会放到一个集合当中(HashMap),
只有放到这个HashMap集合中的,servlet才能够被web容器管理,自己new的servlet对象
不会被web容器管理。(自己new的servlet对象不在容器当中)
(web容器底层有一个HashMap集合,在这个集合中存储了Servlet对象和请求路径之间的关系)
5. 研究:服务器在启动时候,Servlet对象有没有创建出来(默认情况)?
在servlet中提供一个无参数构造方法,启动服务器的时候看构造方法是否执行。
经过测试得出结论,默认情况下,服务器在启动的时候Servlet对象并不会被实例化。
这个设计是合理的,用户没有发送请求之前,如果提前创建,耗费内存。
6. 怎么让服务器启动的时候创建servlet对象
在web.xml servlet标签中添加0子标签,
在子标签中填写整数,越小的整数优先级越高
7. 默认情况下服务器启动时候,AServlet对象并没有被实例化
用户发送第一次请求,空值台输出了一下内容
AServlet无参数构造方法执行了
AServlet init method execute
AServlet service method execute!
根据以上输出内容得出结论:
用户发送第一次请求的时候,Servlet对象被实例化(AServlet的构造方法被执行了
并且执行的是无参数构造方法)
AServlet对象被创建出来之后,Tomcat服务器马上调用了AServlet对象的init方法。
(init方法在执行的时候,AServlet对象已经存在了,已经被创建出来了)
用户发送第一次请求之后,Init方法执行之后,Tomcat服务器马上调用AServlet对象的service方法
8. 用户继续发送第二次请求,控制台输出了一下内容:
AServlet service method execute!
根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet对象并没有新建,
还是使用之前创建好的Servlet对象,直接调用该Servlet对象的service方法,
这说明:
第一: Servlet对象是单例的(单实例的。但是要注意:Servlet对象是单实例的,但是Serlet类并不符合单例模式。我们称之为假单例。
之所以单例是因为Servlet对象的创建我们iavaweb程序员管不着,这个对象的创建只能是Tomcat来说了算,
Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)
9. 关闭服务器-调用destroy方法
AServlet destroy method executed!
destroy方法执行的时候AServlet对象还在,没有被销毁。destroy方法执行结束之后,
AServlet对象的内存才会被Tomcat释放。
10. 适配器
编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。GenericServlet实现Servlet接口。
GenericEervlet是一个适配器。
以后编写的所有Servlet类继承GenericServlet,重写service方法即可。
11. ServletConfig(获取web.xml中的配置信息)接口有4个方法:
第一个方法:
public String getInitParameter(String name);
第二个方法:
public Enumeration getInitParameterNames();
第三个方法:
public ServletContext getServletContext();
第四个方法:
public String getServletName();
以上的四个方法,在自己编写的Servlet类当中也可以使用this取调用,(这个Servlet继承了GenericServlet)
回顾:
·什么是SenvletConfig?
Servlet对象的配置信息对象。
ServletConfig对象中封装了标签中的配置信息。
(web.xml文件中servlet的配置信息)一个Servlet对应一个ServletConfig对象。
Servlet对象是Tomcat服务器创建,并且ServletConfig对象也是Tomcat服务器创建。
并且默认情况下,他们都是在用户发送第一次请求的时候创建。
Tomcat服务器调用Servlet对象的init方法的时候需要传一个ServletConfig对象的参数给init方法。
SerletConfig接口的实现类是Tomcat服务器给实现的。(Tomcat服务器说的就是WEB服务器。)·
ServletConfig接口有哪些常用的方法?
12. ServletContext 上下文对象web.xml
回顾:
1. 一个Servlet对象对应一个ServletConfig。100个Servlet对象则对应100个ServletConfig对象。
2. 只要在同一个webapp当中,只要在同一个应用当中,所有的Servlet对象都是共享同一个ServletContext对象的。
3. ServletContext对象在服务器启动阶段创建,在服务器关闭的时候销毁。这就是ServletContext对象的生命周期。ServletContext对象是应用级对象。
4. Tomcat服务器中有一个webapps,这个webapps 下可以存放webapp,可以存放多个webapp,假设有100个webapp,那么就有100个ServletContext对象。
但是,总之,一个应用,一个webapp肯定是只有一个SenvletContext对象。
5. ServletContext被称为Servlet上下文对象。(Servlet对象的四周环境对象。)
—个ServletContext对象通常对应的是一个web.xml文件。
6. SenvletContext对应显示生活中的什么例子呢?
一个教室里有多个学生,那么每一个学生就是一个Servlet,这些学生都在同一个教室当中,那么我们可以把这个教室叫做ServletContext对象。
那么也就是说放在这个ServletContext对象(环境)当中的数据,在同一个教室当中,物品都是共享的。比如:教室中有一个空调,所有的学生都可以操作。可见,空调是共享的。因为空调放在教室当中。教室就是ServletContext对象。
总结:
ServletContext接口中有哪些常用的方法?
public string getInitPar ameter(String name);//通过初始化参数的name获取value
public Enumeration getInitParameterNames();//获取所有的初始化参数的name
//以上两个方法是Servletcontext对象的方法,这个方法获取的是什么信息?是以下的配置信息
pagesize10
startIndex0
//注意:以上的配置信息J属于应用级的配置信息,一般一个项目中共享的配置信息会放到以上的标签当中。
//如果你的配置信息只是想给某一个servlet作为参考,那么你配置到ser vlet标签当中即可,使用Servletconfig对象来获取。
----------------获取应用的根------------------------------------
public String getContextPath();
获取应用的根路径〈非常重要》,因为在java源代码当中有一些地方可能会需要应用的根路径,这个方法可以动态获取应用的根路径’在java源码当中,
不要将应用的根路经写死,因为你永远都不知道这个应用在最终部署的时候,起一个什么名字。
String contextPath = application.getContextPath();
----------------获取文件的绝对路径(真实路径)----------------------
public String getRealPath(String path);
----------------记录日志----------------------------------------------
public void log(String message);
public void log(String message, Throwable t);
//这些日志信息记录到哪里了?/1/ localhost. 2021-11-05.1og
// Tomcat服务器的1ogs目录下都有哪些日志文件?
//catalina. 2021-11-05.1og服务器端的java程序运行的控制台信息。
//localhost.2021-11-05.1og Servletcont ext对象的1og方法记录的日志信息存储到这个文件中。/ /loca1host_access_log.2021-11-05.txt访问日志
----------------应用域---------------------------------------
//Servletcontext对象还有另一个名字:应用域〈后面还有其他域,例如:请求域、会话域)
//如果所有的用户共享一份数据,并且这个数据很少的被修改,并且这个数据量很少,可以将这些数据放到servletContext这个应用域中
//为什么是所有用户共享的数据?不是共享的没有意义。因为servletContext这个对象只有一个。只有共享的数据放进去才有意义。
//为什么数据量要小?因为数据量比较大的话,太占用堆内存,并且这个对象的生命周期比较长,服务器关闭的时候,这个对象才会被销毁。大数据量会影响服务器的性能。占用内存较小的数据量可以考虑放进去。
//为什么这些共享数据很少的修改,或者说几乎不修改?
//所有用户共享的数据,如果涉及到修改操作,必然会存在线程并发所带来的安全问题。所以放在ServletContext对象中的数据一般都是只读的。
//数据量小、所有用户共享、又不修改,这样的数据放到ServletContext这个应用城当中,会大大提升效率。因为应用域相当于一个级存,放到缓存中的数据,下次在用的时候不需要从数据库中再次获取,大大提升执行效率。
//存(怎么向Servletcontext应用域中存数据》
public void setAttribute(String name, Object value);
//取《怎么从Servletconfext应用域中取数据》
public Object getAttribute(String name);
删(怎么筒除Servletcontext应用域中的数据》
public void removeAttribute(String name);
注意:以后我们编写Serlet类的时候,实际上是不会去直接继承GenericSerlet类的,
因为我们是B/S结构的系统,这种系统是基于HTTP超文本传输协议的,在Servlet规范当中,
提供了一个类叫做HttpServlet,它是专门为HTTP协议准备的一个Sendlet类。我们编写的Servlet类要继承HttpServlet。
(HttpServlet是HTTP协议专用的。)
jakarta.servlet.Servlet(接口)【爷爷】
jakarta.servlet.GenericServlet implements Servlet(抽象类)【儿子】
jakarta.servlet.http.HttpServlet extends GenericServlet(抽象类)【孙子】
我们以后编写的Servlet要继承HttpServlet类
大家到目前为止都接触过哪些缓存机制了?。堆内存当中的字符串常量池。
"abc"先在字符串常量池中查找,如果有,直接拿来用。如果没有则新建,然后再放入字符串常星池。。堆内存当中的整数型常量池。
[-128~127]一共256个Integer类型的引用,放在整数型常量池中。没有超出这个范围的话,直接从常量池中取。
。连接池
这里所说的连接池中的连接是java语言连接数据库的连接对象: java.sql.Connection对象。
MM是一个进程。MySQL数据库是一个进程。进程和进程之间建立连接,打开通道是很费劲的。是很耗费资源的。怎么办?可以提前先创建好N个Connection连接对象,将连接对象放到一个集合当中,我们把这个放有Connection对象的集合称为连接池。每一次用户连接的时候不需要再新建连接对象,省去了新建的环节,直接从连接池中获取连接对象,大大提升访问效率。
连接池
最小连接数最大连接数
连接池可以提高用户的访问效率。当然也可以保证数据库的安全性。
。线程池
Tomcat服务器本身就是支持多线程的。
Tomcat服务器是在用户发送—次请求。就新建—个Thread线程对象吗?
当然不是,实际上是在Tomcat服务器启动的时候,会先创建好N多个线程Thread对象,然后将线程对象放到集合当中,称为线程池。用户发送请求过来之后,需要有一个对应的线程来处理这个请求,这个时候线程对象就会直接从线程池中拿,效率比较高。
所有的WEB服务器,或者应用服务器,都是支持多线程的,都有线程池机制。
redis
NoSql数据库,非关系型数据库,缓存数据库。
。向ServletContext应用域中存储数据,也等于是将数据存放到缓存cache当中了。|
##### HTTP协议
·什么是协议?
。协议实际上是某些人,或者某些组织提前制定好的一套规范,大家都按照这个规范来,这样可以做到沟通无障碍。。协议就是—套规范,就是一套标准。由其他人或其他组织来负责制定的。
。我说的话你能听懂,你说的话,我也能听懂,这说明我们之间是有一套规范的,一套协议的,这套协议就是:中国普通话协议我们都遵守这套协议,我们之间就可以沟通无瞳碍。
·什么是HITP协议?
o HTTP协议:是W3C制刮定的一种超文本传输协议。
。这种协议游走在B和S之间。B向S发数据要遵循HTTP协议。S向B发数据同样需要遵循HTTP协议。这样B和S才能解耦合。。什么是解耦合?
B不依赖S。S也不依赖B。
请求行
请求头
空白行
请求体
· GET请求和POST请求有什么区别?
o get请求发送数据的时候,数据会挂在URI的后面,并且在URI后面添加一个?""?"后面是数据。这样会导致发送的数据回显在浏
览器的地址栏上。(get请求在“请求行""上发送数据)
- http:/localhost:8080/servlet05/getServlet?username=zhangsan&userpwd=1111
o post请求发送数据的时候,在请求体当中发送。不会回显到浏览器的地址栏上。也就是说post发送的数据,在浏览器地址栏上看不到。(post在“请求体"当中发送数据)
o get请求只能发送普通的字符串。并且发送的字符串长度有限制,不同的浏览器限制不同。这个没有明确的规范。o get请求无法发送大数据量。
o post请求可以发送任何类型的数据,包括普通字符串,流媒体等信息:视频、声音、图片。o post请求可以发送大数据量,理论上没有长度限制。
o get请求在W3C中是这样说的:get请求比较适合从服务器端获取数据。o post请求在W3.C中是这样说的: post请求比较适合向服务器端传送数据。
o get请求是安全的。get清求是绝对安全的。为什么?因为get请求只是为了从服务器上获取数据。不会对服务器造成威胁。
o post请求是危险的。为什么?因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器当中,服务器是很危险的。另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会选择拦截(监听) post请求。
o get请求支持缓存。
https:l/n.sinaimg.cn/finance/590/w240h350/20211101/b40c-b425eb67cabc342ff5b9dc018b4b00cc.jpg任何一个get请求最终的"响应结果"都会被浏览器缓存起来。在浏览器缓存当中:;
一个get请求的路径a 对应一个资源。
一个get请求的路径b 对应一个资源。.一个get请求的路径c 对应一个资源。.…
实际上,你只要发送get请求,浏览器做的第一件事都是先从本地浏览器缓存中找,找不到的时候才会去服务器上获取。这种缓存机制目的是为了提高用户的体验。
有没有这样一个需求:我们不希望get请求走缓存,怎么办?怎么避免走缓存?我希望每一次这个get请求都去服务器上找资源,我不想从本地浏览器的缓存中取。
只要每一次get请求的请求路径不同即可。
https://n.sinaimg.cn/finance/590/w240h350/20211101/7cabc342ff5b9dc018b4b00cc.jpg?t=789789787897898https:/n.sinaimg.cn/finance/590/w240h350/20211101/7cabc342ff5b9dc018b4b00cc.jpg?t=789789787897899
o post请求不支持缓存。
post请求之后,服务器"响应的结果"不会被浏览器缓存起来。因为这个缓存没有意义。
o name=value&name=value&name=value&name=value
o name是什么?
以form表单为例: form表单中input标签的name。o value是什么?
以form表单为例: form表单中input标签的value。
.GET请求和POST请求如何选择,什么时候使用GET请求,什么时候使用POST请求?
。怎么选择GET请求和POST请求呢?衡星标准是什么呢?你这个请求是想获取服务器端的数据,还是想向服务器发送数据。如果你是想从服务器上获取资源,建议使用GET请求,如果你这个请求是为了向服务器提交数据,建议使用POST请求。
·不管你是get请求还是post请求,发送的请求数据格式是完全相同的,只不过位置不同,格式都是统一的:
###模板方法设计模式
·什么是模板方法设计模式?
。在模板类的模板方法当中定义核心算法骨架,具体的实现步骤可以延迟到子类当中完成。
·模板类通常是一个抽象类,模板类当中的模板方法定义核心算法,这个方法通常是final的(但也可以不是final的)·模板类当中的抽象方法就是不确定实现的方法,这个不确定怎么实现的事儿交给子类去做。|
### HttpServlet源码分析
HttpServlet类是专门为HTTP协议准备的。比GenericServlet更加适合HTTP协议下的开发。
HttpServlet在哪个包下?
o jakarta.servlet.http.HttpServlet
·到目前为止我们接触了servlet规范中哪些接口?
o jakarta.servlet.Servlet核心接口(接口)
o jakarta.servlet.ServletConfig Servlet配置信息接口(接口)
o jakarta.servlet.ServletContext Servlet上下文接口(接口)
o jakarta.servlet.ServletRequest Servlet请求接口(接口)
o jakarta.servlet.ServletResponse Servlet响应接口(接口)
o jiakarta.servlet.ServletException Servlet异常(类)
o jakarta.servlet.GenericServlet标准通用的Servlet类(抽象类)
http包下都有哪些类和接口呢?
jakarta.serMlet.http.*;
o iakarta.servlet.http.HttpServlet(HTTP协议专用的Servlet类,抽象类)
oiakarta.servlet.http.HttpServletRequest(HTTP协议专用的请求对象)
o iakarta.servlet.http.HttpServletResponse (HTTP协议专用的响应对象)HttpServletRequest对象中封装了什么信息?
o HttpServletRequest,简称request对象。
o HttpServletRequest中封装了请求协议的全部内容。
o Tomcat服务器(WEB服务器)将“请求协议"中的数据全部解析出来,然后将这些数据全部封装到request对象当中了。。也就是说,我们只要面向HttpServletRequest,就可以获取请求协议中的数据。
· HttpServletResponse对象是专门用来响应HTTP协议到浏览器的。
·回忆Servlet生命周期?
o用户第一次请求
. Tomcat服务器通过反射机制,调用无参数构造方法。创建Servlet对象。(web.xml文件中配置的Servlet类对应的对象。)
Tomcat服务器调用Servlet对象的init方法完成初始化。
Tomcat服务器调用Servlet对象的service方法处理请求。o用户第二次请求
Tomcat服务器调用Servlet对象的service方法处理请求。。用户第三次请求
Tomcat服务器调用Servlet对象的service方法处理请求。
Tomcat服务器调用Servlet对象的service方法处理请求。。服务器关闭
Tomcat服务器调用Servlet对象的destroy方法,做销毁之前的准备工作。
Tomcat服务器销毁Servlet对象。
. HttpServlet源码分析:
```
public class He11oservlet extends Httpservlet {
//用户b一次请求,创建He1loservlet对象的时候,会执行这个无参数构造方法。
public He11oservlet(){}
}
public abstract class Genericservlet implements servlet,servletconfig,
java.io.Serializable {
//用户第一次请求的时候,He1loservlet对象第一次被创建之后,这个init方法会执行。
public void init(Servletconfig config) throws ServletException {
this.config = config;
this.init();
}
// 用户第一次请求的时候,带有参数的init执行之后,会执行这个没有带参数的init()
public void init() throws ServletException {
//NOOP by defau1tl
}
}
public abstract class HttpServlet extends GenericServlet {
//用户发送第一次请求的时候这个service会执行
//用户发送第次请求的时候,这个service方法还是会执行。
//用户只要发送一次请求,这个service方法就会执行一次。
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
HttpServletRequest request;
HttpServletResponse response;
try {
// 将ServletRequest和ServletResponse向下转型为带有Http的HttpServletRequest和HttpServletResponse
request = (HttpServletRequest)req;
response = (HttpServletResponse)res;
} catch (ClassCastException var6) {
throw new ServletException(lStrings.getString("http.non_http"));
}
// 调用重载的service方法
this.service(request, response);
}
// 重载的service方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = req.getMethod();
....
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_get_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String msg = lStrings.getString("http.method_post_not_supported");
this.sendMethodNotAllowed(req, resp, msg);
}
}
```
通过以上源码分析:
假设前端发送的请求是get请求,后端程序员重写的方法是doPost
假设前端发送的请求是post请求,后端程序员重写的方法是doGet
会报405错误
怎么避免405的错误呢?
后端重写了doGet方法,前端一定要发get请求。后端重写了doPost方法,前端一定要发post请求。这样可以避免405错误。
这种前端到底需要发什么样的请求,其实应该后端说了算。后端让发什么方式,前端就得发什么方式。
有的人,你会看到为了避免405错误,在Servlet类当中,将doGet和doPost方法都进行了重写。
这样,确实可以避免405的发生,但是不建议,405错误还是有用的。该报错的时候就应该让他报错。
我们编写的HelloServlet直接继承HttpServlet,直接重写HttpServlet类中的service()方法行吗?。
可以,只不过你享受不到405错误。享受不到HTTP协议专属的东西。
·到今天我们终于得到了最终的一个Servlet类的开发步骤:
。第一步:编写一个Servlet类,直接继承HttpServlet
。第二步:重写doGet方法或者重写doPost方法,到底重写谁,javaweb程序员说了算。。第三步:将Servlet类配置到web.xml文件当中。
。第四步:准备前端的页面(form表单),form表单中指定请求路径即可。
#### 关于一个web站点的欢迎页面
·什么是一个web站点的欢迎页面?
。对于一个webapp来说,我们是可以设置它的欢迎页面的。
。设置了欢迎页面之后,当你访问这个webapp的时候,或者访问这个web站点的时候,没有指定任何"资源路径",这个时候会默认访问你的欢迎页面。
。我们一般的访问方式是:
http://localhost:8080/servlet06/login.html
这种方式是指定了要访问的就是login.html资源
。。如果我们访问的方式是:
http:/localhost:8080/servlet06
如果我们访问的就是这个站点,没有指定具体的资源路径。
它默认会访问谁呢?默认会访问你设置的欢迎页面。
怎么设置欢迎页面呢?
。第一步:我在IDEA工具的web目录下新建了一个文件login.html
。第二步:在web.xml文件中进行了以下的配置
``
login.html
``
注意:设置欢迎页面的时候,这个路径不需要以"""开始。
并且这个路径默认是从webapp的根下开始查找。
。第三步:启动服务器。浏览器地址栏输入地址
http://localhost:8080/servlet07
如果在webapp的根下新建一个目录,目录中再给一个文件,那么这个欢迎页该如何设置呢?。在webapp根下新建page1
。在page1下新建page2目录
。在page2目录下新建page.html页面。在web.xml文件中应该这样配置
`
page1/page2/page.html
`
一个webapp是可以设置多个欢迎页的
`
page1/page2/page.html
login.html
`
注意:越靠上的优先级越高,找不到的继续向下找
不配置,就会默认直接访问index.html,(tomcat服务器已经配置好了)
·你有没有注意一件事:当我的文件名设置为index.html的时候,
不需要在web.xml文件中进行配置欢迎页面。这是为什么?
。这是因为小猫咪Tomcat服务器已经提前配置好了。
。实际上配置欢迎页面有两个地方可以配置:
一个是在webapp内部的web.xml文件中。(在这个地方配置的属于局部配置)
一个是在CATALINA_HOME/conf/web.xml文件中进行配置。
`
index.html
index.htm
index.jsp
`
(在这个地方配置的属于全局配置)
注意原则:
局部优先原则。(就近原则)
也使用servlet配置欢迎页!
#### 关于WEB-INF目录
·在WEB-INF目录下新建了一个文件: welcome.html
·打开浏览器访问: http:/localhost:8080/servlet07/WEB-INF/welcome.html出现了404错误。
·注意:放在WEB-INF目录下的资源是受保护的。在浏览器上不能够通过路径直接访问。
所以像HTML、GS、、 image等静态资源一定要放到WEB-INF目录之外。
### HttpServlet接口详解
。测试结果说明:Tomcat服务器(WEB服务器、WEB容器)实现了HttpServletRequest接口,还是说明了Tomcat服务器实现了Senvlet规范。
而对于我们javaweb程序员来说,实际上不需要关心这个,我们只需要面向接口编程即可。我们关心的是
HttpServletRequest接口中有哪些方法,这些方法可以完成什么功能!!!!
request和response对象的生命周期?
o request对象和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。。—次请求对应一个request。
。两次请求则对应两个request,
HttpSenrvletRequest对象中都有什么信息?都包装了什么信息?
o HttpServletRequest对象是Tomcat服务器负责创建的。这个对象中封装了什么信息?封装了HTTP的请求协议。
。实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP的请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,
然后Tomcat服务器把这些信息封装到HttpServletRequest对象当中,传给了我们iavaweb程序员。
o javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。
#### HttpServletRequest接口中的方法?
。怎么获取前端浏览器用户提交的数据?
Map getParameterMap() 获取map
OEnumeration getParameterNames() 获取map集合中所有的key
string[]getParametervalues (String name) 根据key获取map集合的value
String getParameter(String name) 获取value这个一维是数组当中的第一个元素,这个方法最常用
// 以上的4个方法,和获取用户提交的数据有关系。
思考:如果是你,前端的form表单提交了数据之后,你准备怎么存储这些数据,你准备采用什么样vxx始阳雪云付阳/=双据呢?
■前端提交的数据格式:
username=abc&userpwd=111&aihag=s&aihag=d&aihag=tt
我会采用Map集合来存储:
Map
key存储stringvalue存储string这种想法对吗?不对。
如果采用以上的数据结构存储会发现key重复的时候value覆盖。
key value
---------------------
username abc
userpwd 111
aihao s
aihaott d
这样是不行的,因为map的key不能重复。Map
key存储string
value存储string[]
key value
--------------
username {"abc"}
userpwd {"111"}
aihao {"s", "d", "tt"}
request对象实际上又称为“请求域"对象。
应用域对象是什么?
SeruletContext (Servlet上下文对象。)
什么情况下会考虑向ServletContext这个应用域当中绑定数据呢?
第一:所有用户共享的数据。
第二:这个共享的数据量很小。
第三:这个共享的数据很少的修改操f作。
·在以上三个条件都满足的情况下,使用这个应用域对象,可以大大提高我们程序执行效率。
实际上向应用域当中绑定数据,就相当于把数据放到了缓存(Cache)当中,然后用户访问的时候直接从缓存中取,减少IO的操作,大大提升系统的性能,所以缓存技术是提高系统性能的重要手段。Ⅰ
你见过哪些缓存技术呢?
字符串常量池
整数型常量池[-128~127),但凡是在这个范围当中的Integer对象不再创建新对象,直接从这个整数型常量池中获取。大大提升系统性能。
数据库连接池(提前创建好N个连接对象,将连接对象放到集合当中,使用连接对象的时候,直接从缓存中拿。省去了连接对象的创建过程。效率提升。)
线程池(Tomcat服务器就是支持多线程的。所谓的线程池就是提前先创建好N个线程对象,将线程对象存储到集合中,然后用户请求过来之后,直接从线程池中获取线程对象,直接拿来用。提升系统性能)
后期你还会学习更多的缓存技术,例如:redis.mongoD..…....
ServletContext当中有三个操作域的方法:
void setAttribute(string name,object obj);1/向域当中绑定数据。object getAttribute(String name);//从域当中根据name获取数据。void removeAttribute(string name);//将域当中绑定的数据移除
//以上的操作类似于Map集合的操作。
Map map;
map . put ("name", obj);1/向map集合中放key和value
object obj = map.get ("name");// 通过map集合的key获取value
map.remove("name");//通过Map集合的key册删除key和value这个键值对。
### 请求域对象
“请求域"对象要比"应用域"对象范围小很多。生命周期短很多。请求域只在一次请求内有效。一个请求对象request对应一个请求域对象。一次请求结束之后,这个请求域就销毁了。请求域对象也有这三个方法:
void setAttribute(string name,object obj);//向域当中绑定数据。object getAttribute(string name);//从域当中根据name获取数据。void removeAttribute(String name);//将域当中绑定的数据移除
请求域和应用域的选用原则?
尽量使用小的域对象,因为小的域对象占用的资源较少。
#### 转发请求
跳转
转发(━次请求)
1/第一步:获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
//第二步:调用转发器的forwar d方法完成跳转/转发
dispatcher.forward(request ,response);
//第一步和第二步代码可以联合在一起。
request.getRequestDispatcher("/b").forward(request,response);
两个Servlet怎么共享数据?
将数据放到ServletContext应用域当中,当然是可以的,但是应用域范围太大,占用资源太多。不建议使用。
可以将数据放到request域当中,然后AServlet转发到BServlet,保证AServlet和BServlet在同一次请求当中,这样就可以做到两个Servlet,或者多个Servlet共享同一份数据。
转发的下一个资源必须是一个Servlet吗?
不一定,只要是Tomcat服务器当中的合法资源,都是可以转发的。
例如: html....
注意:转发的时候,路径的写法要注意,转发的路径以“r""开始,不加项目名。
关于request对象中两个非常容易混淆的方法
//uri?username=zhangsan&userpwd=123&sex=1
string username = request.getParameter ("username");
1/之前一定是执行过:request.setAttribute("name" ,new objectO)
object obj = request.getAttribute("name");
1/以上两个方法的区别是什么?
1/第一个方法:获取的是用户在浏览器上提交的数据。
/1/第二个方法:获取的是请求域当中绑定的数据。
#### HttpServletRequest接口的其他常用方法
// 获取客户端的ip地址
String remoteAddr = request.getRemoteAddr();
-------------低版本web容器,请求 乱码问题--------------------------
//get请求在请求行上提交数据
// post请求在请求体中提交数据
// 设置请求体中的字符集,(显然这个方法是处理post请求的乱码问题。)
request.setCharacterEncoding("UTF-8");
// 这种方式并不能解决get请求的乱码问题
//在Tomcat9之前(包括9》,响应中文也是有乱码的,怎么解决这个响应的乱码?response.setContentType("text/htm1 ; charset=UTF-8");
l在Tomcat10之后,包括10在内,响应中文的时候就不在出现乱码问题了。以上代码就不需要设置UTF-8了。
//注意一个细节
//在Tomcat10包括10在内之后的版本,中文将不再出现乱码。(这也体现了中文地位的提升。)
l/ get请求乱码问题怎么解决?
// get请求发送的时候,数据是在请求行上提交的,不是在请求体当中提交的。
l/ get请求乱码怎么解决
//方案:修改CATALINA_HOME/conf/server .xm1配置文件
urlPatterns属性:用来指定Servlet的映射路径。可以指定多个字符串。
loadOnStartUp属性:用来指定在服务器启动阶段是否加载该Servlet。等同于:
#### 使用模板方法设计模式优化oa项目
。上面的注解解决了配置文件的问题。但是现在的oa项目仍然存在一个比较臃肿的问题。
。一个单标的CRUD,就写了6个Servlet。如果一个复杂的业务系统,这种开发方式,显然会导致类爆炸。(类的数量太大。)。
怎么解决这个类爆炸问题?可以使用模板方法设计模式。
·怎么解决类爆炸问题?
。以前的设计是一个请求一个Servlet类。1000个请求对应1000个Servlet类。导致类爆炸。
。可以这样做:一个请求对应一个方法。一个业务对应一个Senvlet类。
。处理部门相关业务的对应一个DeptServlet。处理用户相关业务的对应一个UserSerlet。
处理银行卡卡片业务对应一个CardServlet。
#### 分析使用纯粹Servlet开发Web应用的缺陷
·在Servlet当中编写HTML/CSS/JavaScript等前端代码。存在什么问题?
o java程序中编写前端代码,编写难度大。麻烦。
o java程序中编写前端代码,显然程序的耦合度非常高。o java程序中编写前端代码,代码非常不美观。
o java程序中编写前端代码,维护成本太高。(非常难于维护)
修改小小的一个前端代码,只要有改动,就需要重新编译jawa代码,生成新的class文件,打一个新的war包,重新发布
#### JSP
·我的第一个ISP程序:
。在WEB-INF目录之外创建一个index.jsp文件,然后这个文件中没有任何内容
。·将上面的项目部署之后,启动服务器,打开浏览器,访问以下地址:
o http://localhost:8080/jsp/index.jsp展现在大家面前的是一个空白。
。实际上访问以上的这个: index.isp,底层执行的是: index_jsp.class这个java程序。
。这个inde.x.isp会被tomcat翻译生成index_jsp.jiaxa文件,然后tomcat服务器又会将index_jsp.iava编译生成index_jsp.
。访问index.isp,实际上执行的是index isp.class中的方法。
·jSP实际上就是一个Servlet。
o index.isp访问的时候,会自动翻译生成index_isp.jaxa,会自动编译生成index_jsp.class,
那么index_jsp.这就是一个类
o index_jsp类继承HttplspBase,而HttpIspBase类继承的是HttpServlet
。所以index_jsp类就是一个Servlet类。
o jsp的生命周期和Servlet的生命周期完全相同。完全就是一个东西。没有任何区别。
o jsp和servlet一样,都是单例的。(假单例。)
jsp文件第一次访问的时候是比较慢的,为什么?
。为什么大部分的运维人员在给客户演示项目的时候,为什么提前先把所有的jisp文件先访问一遍。
。第一次比较麻烦:
要把jsp文件翻译生成java源文件
java源文件要编译生成class字节码文件然后通过class去创建servlet对象
然后调用servlet对象的init方法
最后调用servlet对象的service方法。
。第二次就比较快了,为什么?
因为第二次直接调用单例servlet对象的service方法即可。
·JSP是什么?
。JSP是java程序。(JSP本质还是一个Servlet)
。JSP是: JavaServer Pages的缩写。(基于Java语言实现的服务器端的页面。)
o Servlet是JavaEE的13个子规范之一,那么ISP也是JavaEE的13个子规范之一。
oJSP是一套规范。所有的web容器/web服务器都是遵循这套规范的,都是按照这套规范进行的“翻译"
。 每一个web容器/web服务器都会内置一个JSP翻译引擎。|
·开发JSP的最高境界:
。眼前是JSP代码,但是脑袋中呈现的是java代码
- JSP的基础语法
- 在jsp文件中直接编写文字,都会自动被翻译到哪里?
- 翻译到servlet类的service方法的out.write("翻译到这里"),直接翻译到双引号里,被java程序当做普通字符串打印输出到浏览器。
- 在JSP中编写的HTML CSS JS代码,这些代码对于JSP来说只是一个普通的字符串。但是JSP把这个普通的字符串一旦输出到浏览器,
浏览器就会对HTML CSS JS进行解释执行。展现一个效果。
- JSP的page指令(这个指令后面再详细说,这里先解决一下中文乱码问题),解决响应时的中文乱码问题:
- 通过page指令来设置响应的内容类型,在内容类型的最后面添加:charset=UTF-8
- <%@page contentType="text/html;charset=UTF-8"%>,表示响应的内容类型是text/html,采用的字符集UTF-8
- 怎么在JSP中编写Java程序:
- <% java语句; %>
- 在这个符号当中编写的被视为java程序,被翻译到Servlet类的service方法内部。
- 在service方法当中编写的代码是有顺序的,方法体当中的代码要遵循自上而下的顺序依次逐行执行。
- service方法当中不能写静态代码块,不能写方法,不能定义成员变量。。。。。。
- 在同一个JSP当中 <%%> 这个符号可以出现多个。
- <%! %>
- 在这个符号当中编写的java程序会自动翻译到service方法之外。
- 这个语法很少用,为什么?不建议使用,因为在service方法外面写静态变量和实例变量,都会存在线程安全问题,因为JSP就是servlet,
servlet是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在线程安全问题。
- JSP的输出语句
- 怎么向浏览器上输出一个java变量。
- <% String name = “jack”; out.write("name = " + name); %>
- 注意:以上代码中的out是JSP的九大内置对象之一。可以直接拿来用。当然,必须只能在service方法内部使用。
- 如果向浏览器上输出的内容中没有“java代码”,例如输出的字符串是一个固定的字符串,可以直接在jsp中编写,不需要写到<%%> 这里。
- 如果输出的内容中含有“java代码”,这个时候可以使用以下语法格式:
- <%= %> 注意:在=的后面编写要输出的内容。
- <%= %> 这个符号会被翻译到哪里?最终翻译成什么?
- 翻译成了这个java代码: out.print();
- 翻译到service方法当中了。
- 什么时候使用<%=%> 输出呢?输出的内容中含有java的变量,输出的内容是一个动态的内容,不是一个死的字符串。如果输出的是一个固定的字符串,直接在JSP文件中编写即可。
- 在JSP中如何编写JSP的专业注释
- <%--JSP的专业注释,不会被翻译到java源代码当中。--%>
-
- JSP基础语法总结:
- JSP中直接编写普通字符串
- 翻译到service方法的out.write("这里")
- <%%>
- 翻译到service方法体内部,里面是一条一条的java语句。
- <%! %>
- 翻译到service方法之外。
- <%= %>
- 翻译到service方法体内部,翻译为:out.print();
- <%@page contentType="text/html;charset=UTF-8"%>
- page指令,通过contentType属性用来设置响应的内容类型。
- JSP的指令
- 指令的作用:指导JSP的翻译引擎如何工作(指导当前的JSP翻译引擎如何翻译JSP文件。)
- 指令包括哪些呢?
- include指令:包含指令,在JSP中完成静态包含,很少用了。(这里不讲)
- taglib指令:引入标签库的指令。这个到JJSTL标签库的时候再学习。现在先不管。
- page指令:目前重点学习一个page指令。
- 指令的使用语法是什么?
- <%@指令名 属性名=属性值 属性名=属性值 属性名=属性值....%>
- 关于page指令当中都有哪些常用的属性呢?
- JSP的九大内置对象
- jakarta.servlet.jsp.PageContext pageContext 页面作用域
- jakarta.servlet.http.HttpServletRequest request 请求作用域
- jakarta.servlet.http.HttpSession session 会话作用域
- jakarta.servlet.ServletContext application 应用作用域
- pageContext < request < session < application
- 以上四个作用域都有:setAttribute、getAttribute、removeAttribute方法。
- 以上作用域的使用原则:尽可能使用小的域。
- java.lang.Throwable exception
- jakarta.servlet.ServletConfig config
- java.lang.Object page (其实是this,当前的servlet对象)
- jakarta.servlet.jsp.JspWriter out (负责输出)
- jakarta.servlet.http.HttpServletResponse response (负责响应
#### 登录
`
drop table if exists t_user;
create table t_user(
id int primary key auto_increment,
username varchar(255),
password varchar(255)
);
insert into t_user(username,password) values('admin','123456');
insert into t_user(username,password) values('zhangsan','123456');
commit;
select * from t_user;
`
#### session
1. session对象是存储在服务器端的
2. 一个session对象对应一个会话
3. 一次会话中包含多次请求
4. session怎么获取?
HttpSession session = request.getSession();
从服务器中获取当前的session对象
如果没有获取到任何session对象,则新建
HttpSession session = request.getSession(false);
从服务器中获取当前的session对象
如果获取不到session,则不会新建,返回一个null
5. session的实现原理
- JSESSIONID=xxxxxx 这个是以Cookie的形式保存在浏览器的内存中的。浏览器只要关闭。这个cookie就没有了。
在web服务器中有一个session列表,类似于map集合。
这个map集合的key存储的是sessionid
这个map集合的value存储的是对应的session对象
用户发送第一次请求的时候:服务器会创建一个新的session对象,同时给session对象生成一个id,
然后web服务器会将session的id发送给浏览器,浏览器将session的id保存在浏览器的缓存中。
用户发送第二次请求的时候:会自动将浏览器缓存中的sessionid自动发送给服务器。
服务器获取到sessionid,然后从session列表中查找到对应的session对象。
6.为什么关闭浏览器,会话结束?
关闭浏览器之后,浏览器中保存的sessionid消失,下次重新打开浏览器之后,浏览器缓存中没有这个sessionid,
自然找不到服务器中对应的session对象。session对象找不到等同于会话结束。
7. session对象什么时候被销毁?
—种销毁:是超时销毁
。—种销毁:是手动销毁。
#### Listener(监听器)
##### 快捷键
ctrl+f12 查找类方法
alt+insert overrideMethods 重写父类方法