# 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 重写父类方法