JAVA Servlet
Servlet
Servlet是SUN公司提供的一门用于开发动态WEB资源的技术。
SUN公司在其API中提供了一个Servlet接口。
用户若想开发一个动态WEB资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
1、编写一个Java类,实现Servlet接口
2、把开发好的Java类部署到WEB服务器中
Servlet简单编写
一个简单的回显的Java类,这里一个HelloWorld继承了HttpServlet,而跟进去可以发现HttpServlet已经实现了Servlet的接口了,并且还封装了一些东西来让我们方便使用,比如GET POST等的方法...
public class HelloWorld extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Hello World!</h1>");
out.println("</body>");
out.println("</html>");
}
当写完Servlet的类之后,还需要映射到对应的web.xml中的路由,这样web容器类似tomcat来知道你请求的路径是哪个Servlet来进行处理
此时访问/adezz,则由Hello这个类来进行处理请求和回复
<servlet>
<servlet-name>MyHello</servlet-name>
<servlet-class>com.zpchcbd.servlet.Hello</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyHello</servlet-name>
<url-pattern>/adezz</url-pattern>
</servlet-mapping>
Servlet 工作原理
先说下Servlet接口中需要实现的如下方法:
public interface Servlet {
void init(ServletConfig var1) throws ServletException;
ServletConfig getServletConfig();
void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
String getServletInfo();
void destroy();
}
继续看Servlet运行的如下流程图:
1、第一步客户发送http request到ServletContainer(不知道这个是什么东西)
2、然后ServletContainer接受到了
3/4、可以看到ServletContainer在接收Client请求的时候,在第三步和第四步分别创建一个HttpServletRequest实例化的对象和一个HttpServletResponse实例化的对象
5、 ServletContainer又会调用service方法
6/7、service方法就会获取HttpServletRequest,HttpServletResponse这两个实例化的对象进行处理,并且通过对应的http方法来处理HttpServletRequest实例化的对象,将结果设置给HttpServletResponse对象
总结:init()方法仅在服务器装载Servlet时才由服务器执行一次,而每次客户向服务器发请求时,服务器就会调用Service()方法。
1、init的函数:这个函数是当我们的 Servlet运行起来后,服务器会对所需要用到的java类文件进行一次编译生成.class文件,然后在之后的请求中都不会进行重新编译,这也就导致了我们此时在java类文件中怎么修改,web页面都不会出现改变,除非我们重启tomcat服务器,来对Servlet实现重新运行!
2、Service的函数:也是Servlet的核心,负责接受/响应客户的请求。Servlet默认情况下,不管是get请求还是post请求,都会经过service()方法来处理,之后在转到相应的doGet或doPost方法上,比如如下正常的GET请求:
3、 Destroy()方法:仅运行一次。在server端停止且卸载Servlet时运行该方法。
Servlet的上下文Context
什么是Context上下文?就是一个保证能程序运行所依赖的东西,也就是上下文中保存了程序需要运行的必须的东西!
在C里面的Context上下文保存的就是CPU中每个寄存器的数据,每个线程运行都需要一个CPU,那么线程怎么知道自己运行到哪里了,那么依赖的就是Context上下文这个结构体,这个结构体就能够说明当前线程跑到了哪里!
那么这里也是类似的理解,多个Servlets所依赖的上下文就是ServletContext,个人理解就是ServletContext中的一些数据能够保证Servlets稳定运行
所以ServletContext中也会存储着一些信息,比如session会话和一些配置信息,我们这里可以直接看ServletContext源码,它是一个接口
public interface ServletContext //这是一个接口
public static final String TEMPDIR = "javax.servlet.context.tempdir"; //用来存储ServletContext的属性的临时目录
public String getContextPath(); //返回当前ServletContext上下文的路径
public ServletContext getContext(String uripath); // 返回一个URL路径的Context对象,撒子玩意 不太懂
public int getMajorVersion(); //获取主要版本
public int getMinorVersion(); //获取次要版本
public Set<String> getResourcePaths(String path);// 获取所有的资源路径(返回指向资源的所有路径的类似目录的列表),并且返回的是一个String的集合
public URL getResource(String path) //获取路径的资源,不太理解
public Servlet getServlet(String name)//获取指定的Servlet程序的对象
public Enumeration<Servlet> getServlets() //获取所有的Servlet程序的对象,返回时一个Servlet类型的Enumeration
public Enumeration<String> getServletNames(); //获取所有的Servlet程序对象的名称
public Object getAttribute(String name); //获取Servlet中有指定name属性的Servlet对象
public void setAttribute(String name, Object object); //给指定的Servlet对象赋值
public void removeAttribute(String name); //移除指定属性名
public String getServletContextName(); //获取当前ServletContext的名称
....
Servlet的上下文Context的应用
应用1、共享数据
这个就不举例的,只需要知道ServletContext中有个setAttribute 和 getAttribute 就知道怎么用了
应用2、通过web.xml中配置Context-param标签,然后通过ServletContext的getInitParameter方法进行获取
比如你在web.xml中写入该标签
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306</param-value>
</context-param>
<servlet-mapping>
<servlet-name>MYHELLO</servlet-name>
<url-pattern>/myhello</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>MYHELLO</servlet-name>
<servlet-class>com.zpchcbd.servlet.HelloServlet</servlet-class>
</servlet>
然后在HelloServlet继承HttpServlet类中写入:
ServletContext servletContext = this.getServletContext();
String s = servletContext.getInitParameter("mysqlUrl");
resp.getWriter().print(s);
访问对应的映射路径,如下图:
应用3、请求转发
写完如下代码,再写上对应的映射路由,在访问mydis的路由
public class DispatcherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
servletContext.getRequestDispatcher("/myhello").forward(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet-mapping>
<servlet-name>myDis</servlet-name>
<url-pattern>/mydis</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>myDis</servlet-name>
<servlet-class>com.zpchcbd.servlet.DispatcherServlet</servlet-class>
</servlet>
如下图所示,我访问了mydis路由,但是最终访问的确实myhello路径
应用3、读取资源文件
public class PropertiesServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
InputStream inputStream = servletContext.getResourceAsStream("/WEB-INF/classes/db.properties");
Properties properties = new Properties();
properties.load(inputStream);
String s = properties.getProperty("username");
resp.getWriter().print(s);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
<servlet>
<servlet-name>mypro</servlet-name>
<servlet-class>com.zpchcbd.servlet.PropertiesServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>mypro</servlet-name>
<url-pattern>/mypro</url-pattern>
</servlet-mapping>