运行在服务器端Servlet容器中的小程序(服务器将请求封装为对象HttpRequest交给Servlet小程序去执行,对数据进行操作,servlet是帮web服务器处理数的)Servlet就是一个接口,凡是实现这个接口的类我们都称为Servlet
接受请求-->处理请求-->返回响应
①服务器返回客户静态资源,例如:web页面,图片等,WEB服务器擅长提供静态页面不能提供动态即时页面,不能往数据库保存数据
②Servlet :服务器端小程序 -可以提供动态页面 -可以与后台交互-运行在servlet容器中,servlet容器运行在服务器中。比如用户输入用户名和密码,web服务器只会响应一些静态页面自己不会处理这些数据,所以服务器会将请求或响应封装为一个对象作为参数传递给java程序,java程序会去处理这些数据,如果用户名密码正确给客户返回一个页面,否则返回另一页面(所有的java程序(Servlet都会有一个方法service(HttpServletRequest request, HttpServletResponse response)方法,这个方法的参数就是请求和响应))
1.创建一个类实现Servlet接口
2.在web.xml文件中注册servlet(在web.xml文件中配置Servlet)
别名
全类名
别名 //对应的Servert
/requestadress //为Servlet映射一个请求地址 Servlet接受浏览器发给web服务器请求 要有请求地址
客户通过浏览器发送请求给web服务器,如发送的请求为一个地址 如:/requestadress,在配置文件web.XML中会映射这个请求地址给 对应的Servlet(Servlet-name),web服务器通过Servlet-name对应的全类名创建一个Servlet实例 , 通过Servlet实例调用其service()方法完成数据的处理。
- Servlet的生命周期是指Servlet的对象由被创建到被销毁的过程。
- Servlet的生命周期方法:
1.构造器
- Servlet第一次处理请求的时候调用,用于创建Servlet的实例,只会调用一次。
- Servlet是单例,同一个Servlet在服务器中只有一个对象,但是它是多线程的,效率高;
- 它是以多线程的方式调用service()方法,Servlet不是线程安全的,在service()中尽量不要操作全局变量。
2.init()
- 构造器执行以后,init马上被调用,用来做初始化操作,只会调用一次
- 注意如果我们继承的是HttpServlet,那么他的里面有两个init方法。
- 如果要重写只能重写的无参的方法。
3.service()
- 每次处理请求时都会调用service,它用来处理用户发送的请求,会调用多次
- 如果我们通过继承HttpServlet实现Servlet,
我们只需要根据要处理的请求类型,重写doGet或doPost
4.destroy()
- Servlet对象销毁之前调用,用来做一些收尾工作,只会调用一次
每一个Servlet都有其唯一对应的ServletConfig,ServletConfig代表Servlet的配置信息,具体来说就是servlet标签中的内容
Servlet3
com.atguigu.servlet.Servlet3
(初始化参数)
username
root
web服务器对XML进行解析时将其封装成一个对象(就像我们利用dom4j对students.xml 进行解析,并封装成student一样) 获取:由服务器创建,最终作为参数传递到init()方法中,我们可以在init方法中直接使用如果是通过继承HttpServlet,则可以直接调用ServletConfig的方法,因为HttpServlet实现了ServletConfig接口。
功能:1.获取当前Servlet的别名(没用)
2.获取当前Servlet的初始化参数(XML中的)
3.获取ServletContext对象
代表整个的WEB应用,每一个WEB应用都有其唯一的ServletContext对象, ServletContext对象在服务器启动时创建,在服务器停止时销毁
获取:通过ServletConfig的getServletContext()方法获取
功能:
1.获取整个WEB应用的初始化参数
phone
13777788899
2.根据虚拟路径获取资源的真实路径(物理路径)(主要用来文件的上传和下载的)
3.可以作为一个域对象在不同的WEB资源之间共享数据
在创建Servlet都是继承HttpServlet类的方式直接创建,然后重写doGet()和doPost()方法】
(原因:因为HttpServlet继承了GenericServlet,而GenericServlet实现了Servlet接口;实际上当请求到达是还是会直接找原生的service(ServletResqust request,ServletResponse response);而自己的原生service方法在父类HttpServlet中;父类中还有一个重载的service(HttpServletRequest request,HttpServletResponse response)方法,请求到达直接找了原生的service方法,然后把ServletRequest和ServletResponse强转为HttpServletRequset和HttpServletResponse然后调用重载的service方法,在重载的setvice方法中会判断请求是get请求还是post请求,如果是get请求会找doGet方法,如果是post请求会直接找doPost方法,所以我们只需要根据前台是get请求还是post请求来重写doGet方法或doPost方法即可)
当需要处理get请求时重写doGet()方法
当需要处理post请求时重写doPost()方法
需要初始化对象时,重写init()无参方法即可
需要做收尾工作的时候,重写destroy()方法即可
request代表浏览器发送给服务器的请求报文
获取:由服务器创建(服务器将请求报文封装为HttpServletRequest对象),最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用
功能:
[1]获取到浏览器发送的请求参数 :如用户名,密码等参数
request.getParameter(String name) //根据参数名获取参数值
[2]动态的获取项目的名字(主要用来设置绝对路径的)
request.getContextPath();
[3]作为一个域对象在不同的WEB资源之间共享数据
[4]请求的转发
RequestDispatcher dispatcher =request.getRequestDispatcher(String path)
dispatcher.forward(request, response);
request.getServerName() : localhost ;
request.getServerPort() : 8080 ;
request.getContextPath() : /项目名 ;
代表服务器发送给浏览器的响应报文
获取:由服务器创建(服务器将响应报文封装为HttpServletRsponse对象),最终作为参数传递到doGet或doPost方法中,我们可以在这两个方法中直接使用
功能:
[1]可以向浏览器发送一个页面或者是页面片段
response.sendRedirect("欢迎登录
")
[2]做请求的重定向
response.sendRedirect(String path)
[3]将数据写到页面
PrintWriter writer = response.getWriter();
writer.write(new Date());
writer.flush();
writer ose();
1、实现 SingleThreadModel 接口
该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行, 当然也就不存在线程安全的问题。
2、同步对共享数据的操作
使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,在本论文中的Servlet可以通过同步块操作来保证线程的安全。
3、避免使用实例变量
本实例中的线程安全问题是由实例变量造成的,只要在Servlet里面的任何方法里面都不使用实例变量,那么该Servlet就是线程安全的。
对上面的三种方法进行测试,可以表明用它们都能设计出线程安全的Servlet程序。但是,如果一个Servlet实现了SingleThreadModel接口,Servlet引擎将为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销。SingleThreadModel在Servlet2.4中已不再提倡使用;同样如果在程序中使用同步来保护要使用的共享的数据,也会使系统的性能大大下降。这是因为被同步的代码块在同一时刻只能有一个线程执行它,使得其同时处理客户请求的吞吐量降低,而且很多客户处于阻塞状态。另外为保证主存内容和线程的工作内存中的数据的一致性,要频繁地刷新缓存,这也会大大地影响系统的性能。所以在实际的开发中也应避免或最小化 Servlet 中的同步代码;在Serlet中避免使用实例变量是保证Servlet线程安全的最佳选择。Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要特别注意。线程安全问题主要是由实例变量造成的,因此在Servlet中应避免使用实例变量。如果应用程序设计无法避免使用实例变量,那么使用同步来保护要使用的实例变量,但为保证系统的最佳性能,应该同步可用性最小的代码路径
①. Servlet 通常用来servlet主要负责处理请求并且应答浏览器发出的请求. 有 HttpServlet 作为实现类,根据需要覆盖 doGet 或 doPost.
②. Filter:意为 "过滤器". 它除了可以完成 Servlet 的功能之外,它还可以实现资源拦截的效果.若把 Servlet 比喻为要拜访的客户,则 Filter 为访问该客户过程中需要经过的门岗. 它将起到过滤的作用.
③. Servlet 和 Filter 的功能谁更强大 ? Filter 的功能更强大些,因为他还有一个拦截的功能. 因为在其中多一个 API:FilterChain.
1.创建一个类,实现javax.servlet.Filter接口
public class ChartSetFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
chain.doFilter(request, response);
}
public void destroy() {
// TODO Auto-generated method stub
}
}
2.在web.xml文件中配置Filter
ChartSetFilter
ChartSetFilter
com.atguigu.survey.filter.ChartSetFilter
ChartSetFilter
/*
3. 如果有多个过滤器都匹配该请求,顺序决定于web.xml filter-mapping的顺序,在前面的先执行,后面的后执行
构造器:创建Filter实例时调用,Filter实例服务器一旦启动就会被创建
init():实例创建后马上被调用,用来对Filter做一些初始化的操作
doFilter():Filter的主要方法,用来完成过滤器主要功能的方法,每次访问目标资源时都会调用。
destroy():服务器停止时调用,用来释放资源。
监听器可以监听Application、Session、Request对象,当这些对象发生变化就会调用对应的监听方法。
1.用于监听域对象的创建和销毁的
【重要】①ServletContextListener: 用于监听 ServletContext 对象被创建和销毁的监听器
public void contextInitialized ( ServletContextEvent sce );
ServletContext创建时调用
public void contextDestroyed ( ServletContextEvent sce );
ServletContext销毁时调用
②HttpSessionListener: 用于监听 HttpSession 对象被创建和销毁的监听器
public void sessionCreated ( HttpSessionEvent se );
HttpSession对象创建时调用
public void sessionDestroyed ( HttpSessionEvent se );
HttpSession对象销毁时调用
③ServletRequestListener: 用于监听 ServletRequest 对象被创建和销毁的监听器
public void requestInitialized ( ServletRequestEvent sre );
ServletRequest对象创建时调用
public void requestDestroyed ( ServletRequestEvent sre );
ServletRequest对象销毁时调用
步骤:
a.创建一个类实现实现ServletContextListener/HttpSessionListener/ServletRequestListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("哈哈,我是ServletContext,我出生了");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("~~~~(>_<)~~~~,我是ServletContext,我要死了");
}
}
b.在web.xml文件中注册监听器
com.atguigu.web.listener.MyServletContextListener
2.用于监听域对象属性变化(添加属性、替换属性、移除属性... ...)
④ServletContextAttributeListener
public void attributeAdded(ServletContextAttributeEvent scab);
向ServletContext中添加属性时调用
public void attributeRemoved(ServletContextAttributeEvent scab);
从ServletContext中移除属性时调用
public void attributeReplaced(ServletContextAttributeEvent scab);
当ServletContext中的属性被修改时调用
⑤HttpSessionAttributeListener
⑥ervletRequestAttributeListener
步骤:
a.创建一个类实现实现ServletRequestAttributeListener/......Lsitener接口
public class ReqAttrListener implements ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("request域中添加一个属性" + srae.getName() + "=" + srae.getValue());
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("request域中移除一个属性" + srae.getName() + "=" + srae.getValue());
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("request域中一个属性被修改了" + srae.getName() + "=" + srae.getValue());
}
}
b.在web.xml文件中注册监听器
com.atguigu.web.listener.ReqAttrListener
3.感知session监听器
⑦HttpSessionBindingListener监听
⑴在需要监听的实体类实现HttpSessionBindingListener接口
⑵重写valueBound()方法,这方法是在当该实体类被放到Session中时,触发该方法
⑶重写valueUnbound()方法,这方法是在当该实体类从Session中被移除时,触发该方法
⑧HttpSessionActivationListener监听
⑴在需要监听的实体类实现HttpSessionActivationListener接口
⑵重写sessionWillPassivate()方法,这方法是在当该实体类被序列化时,触发该方法
⑶重写sessionDidActivate()方法,这方法是在当该实体类被反序列化时,触发该方法