1、Servlet简介
- Servlet是Sun公司开发动态Web的一门技术
- Sun公司在许多API中提供了一个接口叫做:Servlet,如果想开发一个Servlet程序,只需完成两步骤:
- 编写一个类,实现Servlet(重写其中的方法)
- 把开发好的程序部署到Web容器中(我这里用的是Tomcat服务器
2、Servlet原理
- 客户端向Web容器发送Http请求
- Web容器接收到请求后会去调用HttpServlet类中的service方法(HttpServlet类重写了Servlet接口中的service方法),传入Request(请求)和Response(响应)两个参数
- 我们重写service方法,再由Web容器读取我们自己封装好的响应
3、HelloServlet
- 新建一个空的Maven项目,删除里面的src目录,将其作为我们的主工程
- 在主工程中导入依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
- 在主工程目录下新建一个Model,主工程就为该Model的父项目,类似于继承,并在子项目的porn.xml中将主工程配置为parent(我要手动配置才可以使用父项目的依赖,可能是idea版本的问题)
<parent>
<artifactId>xxx</artifactId>
<groupId>xxx</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
- Maven环境优化
- 修改子项目Model中的web.xml配置为最新的(去Tomcat中webapp目录下找一个自带的Web程序的web.xml配置,不同版本的Tomcat都不一样)
- 将Maven的结构搭建完整(在main目录下新建java和resources目录)
- 编写一个Servlet程序
public class HelloServlet extends HttpServlet {
@Override//重写service方法中用到的doGet方法
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置页面显示的类型,支持中文
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//在页面上显示HelloServlet
PrintWriter writer = resp.getWriter();
writer.println("你好,Servlet");
System.out.printf("HelloServlet返回doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
}
- 编写Servlet映射
为什么需要映射:我们编写的是java程序,但是要通过浏览器访问,浏览器需要和Web服务器通信,所以我们需要在Web服务器中注册我们写的Servlet,还需要给它一个浏览器可以访问的路径。同样是在web.xml中配置
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.XXX.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
- 配置Tomcat
配置项目发布的路径,给它一个映射
4、servlet-mapping的一些问题
- 指定默认路径
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.XXX.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
- 指定一些后缀或者前缀(可以自定义后缀请求路径,但“*”前不能加请求路径)
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.XXX.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.hello</url-pattern>
</servlet-mapping>
- 优先级问题
指定了固有路径的优先级最高,如果没有找到,则会走默认路径
5、ServletContext的应用
Web容器在启动之前,会为每个Web应用程序都创建一个对应的ServletContext对象,它就代表了当前的Web应用,意思就是说在所有Web应用程序之上有一个ServletContext对象,可以保存一些数据。
一个Servlet程序把数据保存到ServletContext中,其他Servlet程序可以从中取出
- 放置数据的类
public class SetServletContext extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String userName = "user123";
servletContext.setAttribute("user", userName);
//将一个数据保存在ServletContext中,key为user,value为userName
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
- 读取数据的类
public class GetServletContext extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String user = (String) servletContext.getAttribute("user");
PrintWriter writer = resp.getWriter();
writer.println(user);
}
}
- web.xml的配置(得先写入数据才能去读取,直接读取的话显示的是null)
<servlet>
<servlet-name>setA</servlet-name>
<servlet-class>com.XXX.servlet.SetServletContext</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>setA</servlet-name>
<url-pattern>/setA</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>getA</servlet-name>
<servlet-class>com.XXX.servlet.GetServletContext</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>getA</servlet-name>
<url-pattern>/getA</url-pattern>
</servlet-mapping>
- web.xml配置初始的参数
<context-param>
<param-name>jdbc</param-name>
<param-value>jdbc:mysql://localhost:3306/xxx?xxx</param-value>
</context-param>
- 读取初始化的参数
public class GetParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
String initParameter = servletContext.getInitParameter("jdbc");
resp.getWriter().println(initParameter);
}
}
请求转发和重定向不一样,页面的路径不会改变,但会显示想访问路径的内容
public class Forward extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = this.getServletContext();
servletContext.getRequestDispatcher("/getP").forward(req, resp);//想显示的页面路径
}
}
- 在resources目录下新建db.properties文件,也可以新建在java目录下,不过需要在子项目的porm.xml进行配置,否则没法顺利打包,最后都会打包到classes目录下,俗称这个路径为classpath
user = root
password = www.XXX.com
- 读取资源文件
public class GetProperties extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
resp.setCharacterEncoding("utf8");
//把资源变成一个数据流,路径为最后打包在target目录下的路径
InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
//读取数据流
Properties prop = new Properties();
prop.load(resourceAsStream);
String user = prop.getProperty("user");
String pwd = prop.getProperty("password");
resp.getWriter().print("<h1>" + "姓名:" + user + " 密码:" + pwd + "</h1>");
}
}