JavaWeb笔记——Servlet基础、ServletContext
狂神网课笔记,自用
一、HelloServlet程序
1.1 Servlet概述
- Servlet是开发动态web一种技术,是实现了Servlet接口的java程序
- 用法:编写类实现Servlet接口;把开发好的java类部署到web服务器中。
- 原理:
1.2 配置Servlet的依赖包
- 新建一个非骨架的普通maven
- 删掉原有的src文件,基于该项目可以建立很多的Moudel
- 建立Maven的主文件,在pom.xml中添加servlet的依赖包,在mvnrepository中查找并选择最新的版本,当前是4.0.1
Java Servlet API
Maven依赖:https://mvnrepository.com/
- 将Servlet下Maven的依赖复制到pom.xml的标签dependencies中。
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
- Maven在联网时会自动向本地仓库下载该版本,可以在本地仓库对应的地址下找到。如果本地库内没找,但pom.xml不报红,可以进set检查本地库地址是否正确
- 如果存在依赖包标红,可能是Maven未能自动更新,手动刷新一下。
- 如果Maven不能自动下载,也可以在Maven依赖:https://mvnrepository.com/的官网上手动下载jar包,再解压放入对应的目录中。
1.3 构建javaweb的Moudel
-
右击工程,用骨架方式构建webapp的新模块,子模块下的目录补充完整(如java、resources等)
-
成功后,父工程的pom.xml中,标签modules含有子工程;子工程的pom.xml中,标签parent出现父工程。
-
** 父项目中的jar包,子项目可以直接使用;子项目的jar包,父项目不可以使用**,类同于java中的继承extends。
1.4 编写Servlet程序
- Servlet接口默认的实现类:HttpServlet、GenericServlet
- 在构建的模块下的java中新建一个Java类,直接继承HttpServlet,会自动增加import依赖包。其中,子项目没有导入servlet依赖包,而是直接使用了父项目的依赖包。
- 继承关系:Servlet接口->GenericServlet->HttpServlet->编写的类,所以编写的类直接继承Httpervlet即可。
- 重写方法:如3所述,只需要重写和HttpServlet相关的方法,一般重写doGet和doPost。
重写窗口的快捷键:Alt+Fn+Insert,IDEA环境使用方法杂记(持续打补丁)
public class helloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("进入DoGet方法");//后台打印
PrintWriter writer = resp.getWriter();//响应流
writer.print("HelloServlet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);//由于get和post只是请求实现的不同方式,可以相互调用,业务逻辑一样
}
}
1.5 在web服务中注册Servlet
- 在模块的web.xml文件中,先还原到简单的配置内容
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
</web-app>
- 在标签web-app下配置标签servlet和标签servlet-mapping。
(1)两个标签的-name需要一致;
(2)servlet-class是java包下的地址,如图是liquor.helloServlet
(3)url-pattern是配置了一个访问目录
<!--注册Servlet-->
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>liquor.helloServlet</servlet-class>
</servlet>
<!--Servlet的请求路径-->
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>
- Servlet-mapping指定路径问题:
(1)一个servlet可以指定一个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello-servlet</url-pattern>
</servlet-mapping>
(2)一个servlet可以指定多个映射路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello-servlet-01</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello-servlet-02</url-pattern>
</servlet-mapping>
(3)一个Servlet可以指定调用映射路径,使用*可以进入所有后缀路径
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello-servlet/*</url-pattern>
</servlet-mapping>
(4)可以自定义后缀实现请求映射,*之前不能增加映射路径,例子中,以do结尾就能访问,包括/hello/qwer.do和/qwer.do
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
(5)优先级问题:指定了固有的映射优先级最高,如果没有事先固定则会走默认处理的请求;如:同时具有如下两个映射时,地址/hello进入hello而不会进入默认的error。
<servlet-mapping>
<servlet-name>error</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
1.6 配置Tomcat并运行验证
配置方法见:JavaWeb笔记——环境配置Tomcat、Maven
注意:部署时默认模块具有模块目录,访问的时候注意一下,或者可以删除
-
在web上运行正确的配置地址目录,前端显示结果
-
后台也成功打印输出
二、ServletContext对象
2.1 ServletContext理论
- web容器启动时,每个web会创建一个对应的ServletContext对象针对web应用管理;
- 获得ServletContext类:
ServletContext context= this.getServletContext();
2.2 共享数据——setAttribute()、getAttribute()
-
在某个Servlet中保存的数据,在另一个Servlet中应用;后期使用Session、Resquest替代
-
语法:通过标签访问数据
context.setAttribute("标签名",数据);
(强制转换类型) context.getAttribute("标签名");
- 实例:建立两个类,类HelloServlet的doGet方法将数据存入ServletContext;类UserInfo的doGet方法将数据从ServletContext中读出。
1)类HelloServlet的doGet方法
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HelloServlet");//后台打印,确认正常进入该方法
PrintWriter writer = resp.getWriter();//响应流
writer.print("HelloServlet_01");//页面打印信息
ServletContext context_01 = this.getServletContext();//获取ServletContext类
int userOld = 99;
String userName = "liquor";
context_01.setAttribute("userOld",userOld);//建立结点uerOld,存储数据
context_01.setAttribute("userName",userName);
}
2)类UserInfo的doGet方法, 在ServletContext中数据存储的都是Object类型,在读取时进行强制转换到需要的类型
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context_02 = this.getServletContext();
//在ServletContext中存储的都是Object类型,在读取时进行强制转换到需要的类型
String userName = (String) context_02.getAttribute("userName");
int userOld = (int) context_02.getAttribute("userOld");
resp.setContentType("text/html");//设置内容形式
resp.setCharacterEncoding("utf-8");//设置编码类型
resp.getWriter().println("用户姓名:"+userName);
resp.getWriter().print("用户年龄:"+userOld);
}
3)运行实验1:先运行/HelloServlet后运行/UserInfo,正常获得数据
4)运行实验2:重启tomcat服务器,直接运行/UserInfo,得到空指针的报错,因为没有运行/HelloServlet,没有放入数据,出现了空指针报错。
2.3 获取初始化参数——getInitParameter()
- 在web.xml中,使用标签context-param可以初始化一些公用参数,getInitParameter方法可以获得该参数的内容。基本不用。
- 语法:返回String类型
context.getInitParameter("参数名");
- 实例:
1)web.xml中初始化的参数:
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
2)类GetInitParam中的doGet方法:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context_03 = this.getServletContext();
String url = context_03.getInitParameter("url");
resp.getWriter().println(url);
}
3)在web.xml中注册类GetInitParam
4)运行结果:
2.4 请求转发——getRequestDispatcher().forward()
- 网页需要使用其他网页时,进行转发操作,但网页的目录不改变,和重定位区分
- 语法:
context_04.getRequestDispatcher("/跳转页面").forward(req,resp);
- 实例:
1)类GetRequestD中的doGet方法:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context_04 = this.getServletContext();
System.out.println("进入了类GetRequestD的doGet方法");
context_04.getRequestDispatcher("/GetInitParam").forward(req,resp);//跳转页面
// 上式可以分开写,如下,但没必要;
// RequestDispatcher getReqDispatcher = context_04.getRequestDispatcher("/GetInitParam");
// getReqDispatcher.forward(req,resp);
}
2)在web.xml中注册类GetRequestD
3)运行结果:网页目录还是"/GetRequestD",但显示/GetInitParam的内容。
2.5 读取资源文件——getResourceAsStream()
在模块中建立后缀为.properties的资源文件,进行非绝对地址方式的读取
2.5.1 在resources下构建资源文件
一般在**src->main->resources**文件下建立.properties。
运行tomcat部署后,会在**target->模块名称->WEB-INF->classes**下显示对应的.properties文件
如果模块没有target目录,新建一个重新运行tomcat即可。
2.5.2 在java下构建资源文件
如果.properties文件在**src->main->java**路径下,
运行tomcat时可能存在target对应路径下没有出现对应.properties的情况。
解决方案:需要修改maven中的pom.xml配置,在标签build内加入打包文件的设置标签resources。刷新一下Maven,clean一下模块的生命周期,再重新启动tomcat。
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
刷新maven并clean生命周期:
显示结果:
2.5.3 读取java和resoures目录下的资源文件
-
target->项目名称->WEB-INF->classes俗称为classpath,在读取资源文件时,以target->项目名称为根目录。
-
按照2.5.1和2.5.2所述添加db_01和db_02;
- 类GetPropertiesInfo的doGet方法:
ServletContext获取资源流 -> 新建Properties类加载该资源 -> 显示
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext context_05 = this.getServletContext();
//获取资源文件流,以target->模块名称为根目录,查询/WEB-INF/classes/下的资源文件
InputStream db_01 = context_05.getResourceAsStream("/WEB-INF/classes/db_01.properties");
InputStream db_02 = context_05.getResourceAsStream("/WEB-INF/classes/liquor/db_02.properties");
//加载
Properties prop_db_01 = new Properties();
Properties prop_db_02 = new Properties();
prop_db_01.load(db_01);
prop_db_02.load(db_02);
//显示
String db_01_username = prop_db_01.getProperty("username");
String db_01_password = prop_db_01.getProperty("password");
resp.getWriter().println(db_01_username+":"+db_01_password);
String db_02_username = prop_db_02.getProperty("username");
String db_02_password = prop_db_02.getProperty("password");
resp.getWriter().println(db_02_username+":"+db_02_password);
}
- 在web.xml注册类GetPropertiesInfo;
- 运行结果: