文章目录
Servlet概述
1、什么是Servlet
- 接受请求数据
- 处理请求
- 完成响应
2、实现Servlet的方式
实现Servlet有三种方式
实现:javax.servlet.Servlet 接口;
继承:javax.servlet.GenericServlet 类;
继承:javax.servlet.http.HttpServlet 类;
3、生命周期
- 生命周期方法:
- void init(ServletConfig):出生之后;
- void service(ServletRequest request , ServletResponse response) :每次处理请求都会被调用
- void destroy(): 临死之前;
- 特性:
- 单例 : 一个类只有一个对象,当然可能存在多个Servlet类
- 属于线程不安全 , 效率高
- Servlet类由开发者编写,对象有服务器创建,并由服务器调用相应的方法;
4、ServletConfig
GenericServlet
HttpServlet
- protected void doGet(HttpServletRequest req,HttpServletResponse resp)throws ServletException,
IOException- protected void doPost(HttpServletRequest req,HttpServletResponse resp)throws ServletException,
IOException
Servlet细节
1、Servlet与线程安全
- 不要在Servlet中创建对象!创建局部变量即可
- 可以创建无状态成员
- 可以创建有状态成员,但状态必须为只读的
2、让服务器启动时就创建Servlet
3、<url–pattern>
4、web.xml文件的(继承)
- 404 -> default
- org.apache.catalina.servlets.DefaultServlet
- jsp -> jsp
- org.apache.jasper.servlet.JspServlet
5、Servlet与反射
- 通过web.xml中类名的路径反射创建实例
ServletContext
- 一个项目只有一个ServletContext对象
- 可以在N多个Servlet中获取这唯一的对象,使他可以给多个Servlet传递数据
- 与天地同寿!!! 这个对象在tomcat启动时就创建,在Tomcat关闭时才会死去
1、ServletContext概述
2、获取ServletContext
在ServletContext中获取ServletContext对象
-
ServletConfig类的getServletContext()可以获取ServletContext对象
- 在void(ServletConfig servletConfig)中:ServletContext servletContext = servletConfig.getServletContext();
-
在GenericeServlet或HttpServlet中获取ServletContext对象
- GenericeServlet类有getServletContext(),所以可以直接使用this.getServletContext()来获取
3、域对象功能
- 存储一个对象:public void setAttribute(String name,Object object);
- 获取ServletContext中的数据:public Object getAttribute(String name);
- 移除ServletContext中的域属性:public void removeAttribute(String name);
- 获取所有属性的名称:public Enumeration getAttributeNames();
4、获取应用初始化参数
5、获取资源的相关方法
1、获取真实路径
/**
* 得到盘符路径
* D:\WebStorm\TomCat\apache-tomcat-9.0.34\webapps\Web\login.html
*/
String path = this.getServletContext().getRealPath("/login.html");
System.out.println(path);
2、获取资源流
/**
* 获取资源路径, 在创建输入流对象
*/
InputStream input = this.getServletContext().getResourceAsStream("/login.html");
3、获取指定目录下所有的资源路径
/**
* 获取当前路径下所有资源的路径
* [/WEB-INF/lib/, /WEB-INF/classes/, /WEB-INF/web.xml]
*/
Set<String> paths = this.getServletContext().getResourcePaths("/WEB-INF");
System.out.println(paths);
这些方法必须从“/”开头
6、练习:访问量统计
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 获取servletContext对象
* 从ServleContext对象中获取名为count的属性
* 如果存在:给访问量加1,然后在保存回去
* 如果不存在:说明是第一次访问,向ServletContext中保存名为count的属性,值为1
*/
ServletContext application = this.getServletContext();
Integer count =(Integer)application.getAttribute("count");
if(count == null) {
application.setAttribute("count", 1);
}else {
application.setAttribute("count", count + 1);
}
/**
* 向浏览器输出
* 使用相应对象
*/
PrintWriter pw = resp.getWriter();
pw.print("<h1>" + count + "</h1>");
}
获取类路径下的资源
- Class
- ClassLoader
BaseServlet
public abstract class BaseServlet extends HttpServlet { @Override public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /** * 获取参数,用来识别用户想请求的方法 * 然后判断是哪一个方法,是哪一个就调用哪一个 */ String methodName = req.getParameter("method"); if(methodName == null || methodName.trim().isEmpty()) { throw new RuntimeException("您没有传递method参数!无法确定您想要调用的方法"); } /** * 得到方法名称,通过方法名在得到Method类的对象 * 需要的到Class,然后调用他的方法进行查询!得到Method * 要查询当前类的方法,所以需要得到当前类的Class */ Class c = this.getClass(); //得到当前class对象 Method method = null; try { method = c.getMethod(methodName, HttpServletRequest.class , HttpServletResponse.class); } catch (Exception e) { throw new RuntimeException("您要调用的方法" + methodName + "(HttpServletRequest,HttpServletResponse),它不存在"); } /** * 调用method表示的方法 */ try { method.invoke(this, req,resp); // this.addUser(req,resp) ,method(this,req,resp) } catch (Exception e) { System.out.println("您要调用的方法:" +methodName + ",它内部抛出了异常!"); throw new RuntimeException(e); } } }
- 转发:req.getRequestDispatcher("/xxx").forward(req, resp); 不改变地址位置
- 重定向:resp.sendRedirect(req.getContextPath()+"/xxx.jsp"); 改变地址位置
package cn.itcast.servlet;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public abstract class BaseServlet extends HttpServlet {
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
/**
* 获取参数,用来识别用户想请求的方法
* 然后判断是哪一个方法,是哪一个就调用哪一个
*/
String methodName = req.getParameter("method");
if(methodName == null || methodName.trim().isEmpty()) {
throw new RuntimeException("您没有传递method参数!无法确定您想要调用的方法");
}
/**
* 得到方法名称,通过方法名在得到Method类的对象
* 需要的到Class,然后调用他的方法进行查询!得到Method
* 要查询当前类的方法,所以需要得到当前类的Class
*/
Class c = this.getClass(); //得到当前class对象
Method method = null;
try {
method = c.getMethod(methodName, HttpServletRequest.class , HttpServletResponse.class);
} catch (Exception e) {
throw new RuntimeException("您要调用的方法" + methodName + "(HttpServletRequest,HttpServletResponse),它不存在");
}
/**
* 调用method表示的方法
*/
try {
String result = (String)method.invoke(this, req,resp); // this.addUser(req,resp) ,method(this,req,resp)
/**
* 获取请求处理方法执行后返回字符串 ,它表示转发或重定向的路径!
* 帮它完成转发或者重定向
*/
/**
* 如果用户返回的是字符串为null,或"",那什么也不用做
*/
if(result == null || result.trim().isEmpty()) {
return ;
}
/**
* 查看返回的字符串是否包含冒号,如果没有默认为转发
* 如果有,使用冒号分割字符串,得到前缀和后缀
* 其中前缀如果是f,表示转发,如果是r表示重定向,后缀就是要转发或者重定向的路径
*/
if(result.contains(":")) {
//使用冒号分割字符串,得到前缀和后缀
int index = result.indexOf(":"); // 获取冒号的位置
String s = result.substring(0, index);// 截取出前缀,表示操作
String path = result.substring(index);//截取出后缀,表示路径
if(s.equalsIgnoreCase("r")) {//如果前缀是r,那么重定向
resp.sendRedirect(req.getContextPath() + path);
}else if (s.equalsIgnoreCase("f")) {//如果前缀是f,那么转发
req.getRequestDispatcher(path).forward(req, resp);
}else {
throw new RuntimeException("您指定的操作" + s + ",当前版本还不支持!");
}
}else {// 没有冒号 默认为转发
req.getRequestDispatcher(result).forward(req, resp);
}
} catch (Exception e) {
System.out.println("您要调用的方法:" + methodName + ",它内部抛出了异常!");
throw new RuntimeException(e);
}
}
}
;
}else if (s.equalsIgnoreCase(“f”)) {//如果前缀是f,那么转发
req.getRequestDispatcher(path).forward(req, resp);
}else {
throw new RuntimeException(“您指定的操作” + s + “,当前版本还不支持!”);
}
}else {// 没有冒号 默认为转发
req.getRequestDispatcher(result).forward(req, resp);
}
} catch (Exception e) {
System.out.println("您要调用的方法:" + methodName + ",它内部抛出了异常!");
throw new RuntimeException(e);
}
}
}