相关链接:
文章目录
4.1.1 tomcat 部署静态资源
步骤:
- 目标:浏览器正常访问http://127.0.0.1/test/hello.html
在tomcat/webapps下创建文件夹test,在test文件夹下创建hello.html - 在终端启动tomcat
- 进入网址127.0.0.1:8080,查看tomcat是否启动成功
- 进入网址127.0.0.1:8080/test/hello.html,查看是否能正确打开
代码:
win系统只需要在tomcat/bin下找到startup.bat和shutup.bat即可启动/关闭。
mac电脑在终端启动/关闭tomcat:
我用的是方法3
启动的代码:
cd /Library/apache-tomcat-9.0.67/bin
sudo chmod 755 /Library/apache-tomcat-9.0.67/bin/*.sh
sudo sh startup.sh
关闭的代码:
cd /Library/apache-tomcat-9.0.67/bin
sudo chmod 755 /Library/apache-tomcat-9.0.67/bin/*.sh
sudo sh shutdown.sh
实验结果:
http://127.0.0.1/test/hello.html可正常访问
4.1.2
步骤:
- 测试环境变量是否javac,下图为已配置javac
- 在终端处输出javac “A.java的地址” -cp “servlet-api.jar文件的地址”
代码:
实验结果:
4.1.4 Servlet生命周期
步骤:
我们会发现B.java中没有main方法,也就是说并不是作为普通的java程序执行的,那么这些对象什么时候会被加载、执行呢?
我们可以观测一下它的生命周期。
在方法上打一些输出信息,通过输出信息观察它的生命周期。
Init()方法在程序启动时被调用了一次,Service()方法每访问一次网页都会调用一次,destroy()方法在停掉servlet时会被调用一次。
代码:
@WebServlet("/bbb")
public class B implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("call init()");
}
@Override
public ServletConfig getServletConfig() {
System.out.println("call getServletConfig()");
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("call service()");
servletResponse.getWriter().println("hello bbbb3");
}
@Override
public String getServletInfo() {
System.out.println("call getServletInfo()");
return null;
}
@Override
public void destroy() {
System.out.println("call destroy()");
}
}
实验结果:
有两个方法被调用到了,init()方法和service()方法
每刷新一次,service()方法都会得到调用,init()方法只会执行一次
停掉Servlet执行了destroy()方法
4.1.5 继承 GenericServlet
代码:
@WebServlet("/ccc")
public class C extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
servletResponse.getWriter().write("hello c");
}
}
实验结果:
4.1.6 继承HttpServlet
步骤:
- 创建D.java文件
- 调用doGet方法,用resp的getWriter()方法输出context的路径
- 通过super调用父类里的doGet方法,运行程序,结果会报错405,并且有乱码
- 解决乱码:加一句:
resp.setContentType(“text/html;charset=utf-8”)
response.setContentType(MIME)例如web浏览器就是通过MIME类型来判断文件是GIF图片。通过MIME类型来处理json字符串。
代码:
@WebServlet("/ddd")
public class D extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
super.doGet(req, resp);
resp.getWriter().append("Served at: ").append(req.getContextPath());
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实验结果:
解决乱码后:
4.1.7 Servlet的URL配置
步骤:
- 创建
ServletA、ServletB、ServletC
三个java文件,调用resp
的getWrite()
方法,分别输出<h1>ServletA或B或C</Servlet>
- 在web.xml文件中配置URL
- ServletA的URL配置语句中
其中:/a,/aa为准确匹配;/a/*为路径匹配;/*也为路径匹配,代表所有的 - ServletB的URL配置语句中
其中:/b为精确匹配,*.do扩展名匹配(扩展名匹配和路径匹配两者只能选一个) - ServletC的URL配置语句中
其中:/c为精确匹配,/为默认匹配(如果其他Servlet都不能满足,我们就默认选它) - 在@WebServlet()中配置URL
代码:
ServletA(import部分省略)
//@WebServlet({"/a","/aa"})
public class ServletA extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("# call service A");
servletResponse.setContentType("text/html;");
servletResponse.getWriter().write("<h1>ServletA</h1>");
}
}
web.xml
<servlet>
<servlet-name>testA</servlet-name>
<servlet-class>test.mapping.ServletA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testA</servlet-name>
<!-- <url-pattern>/*</url-pattern>-->
<url-pattern>/a/*</url-pattern> <!--路径匹配:只要是/a开头的都可以-->
<url-pattern>/a</url-pattern>
<url-pattern>/aa</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testB</servlet-name>
<servlet-class>test.mapping.ServletB</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testB</servlet-name>
<url-pattern>*.do</url-pattern> <!-- -->
<url-pattern>/b</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testC</servlet-name>
<servlet-class>test.mapping.ServletC</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testC</servlet-name>
<url-pattern>/</url-pattern> <—默认匹配-->
<url-pattern>/c</url-pattern> <!--精确匹配-->
</servlet-mapping>
实验结果:
精确匹配:
其他匹配:
/a/x.do:路径比配优先级比更高
/*打开后:
ServletC的/和ServletA的/*都注释掉
两个都不注释的结果:
只注释/的结果是ServletC
4.1.8 ServletConfig接口的使用
步骤:
- 创建项目ch0403,创建ServletConfigTest.java,实现一个接口Sevrlet,实现接口里的4个抽象方法:init(), getServletConfig(), service(), getServletInfo(), destroy()
- 通过web.xml配置Servlet的url
- 在web.xml的中配置三组初始化参数:…
- 这些参数,如何让程序输出呢?通过init()方法得到参数。Tomcat在调用init()方法时,会把三组参数封装在ServletConfig里面,就可以用config拿到。getInitParamter()拿到参数对应的值,sout输出在控制台。
- 定义一个config对象。Init()方法调用时,参数config被tomcat传进来了,就把它保存下来。保存:this.config = config,tomcat传进来的是config,把它赋值到this.config,即我们在外面定义的对象,那么外面的config就有值了。
- getServlet()方法返回config
- 程序运行时,想在浏览器页面上输出,就需要在service()里调用getServletConfig()方法拿到config,再用resp的getWrite()方法输出
- 通过getInitParameterNames()方法拿到所有参数的名字,接口Enumeration有一个方法hasMoreElements(),它返回true,表示还有下一个元素。用Enumeration接口nextElement()方法取出下个元素。
- 用config的getInitParamter方法拿到参数对应的值
- 再输出参数名和值。
代码:
Java代码:
@WebServlet(value = "/config2", initParams = {
@WebInitParam(name = "user", value = "114"),
@WebInitParam(name = "pwd", value = "444"),
},loadOnStartup = 2)
public class ServletConfigTest implements Servlet {
private ServletConfig config;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
this.config=servletConfig;
System.out.println(servletConfig.getServletName());
System.out.println(servletConfig.getInitParameter("user"));
System.out.println(servletConfig.getInitParameter("pwd"));
System.out.println(servletConfig.getInitParameter("maxtimes"));
Enumeration<String> paramNames = servletConfig.getInitParameterNames();
while (paramNames.hasMoreElements()){
String paramName = paramNames.nextElement();
String value = config.getInitParameter(paramName);
System.out.println(paramName + "->" + value);
}
}
@Override
public ServletConfig getServletConfig() {
return config;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletConfig config = getServletConfig();
servletResponse.getWriter().println("in servletConfig test, user:" + config.getInitParameter("user"));
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
web.xml文件的代码:(用来配置初始化参数)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>testConfig</servlet-name>
<servlet-class>ServletConfigTest</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>zhang3</param-value>
</init-param>
<init-param>
<param-name>pwd</param-name>
<param-value>333</param-value>
</init-param>
<init-param>
<param-name>maxtimes</param-name>
<param-value>3</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>testConfig</servlet-name>
<url-pattern>/config</url-pattern>
</servlet-mapping>
</web-app>
实验结果:
倒数第三行为null,是因为在@WebServlet()中我们没给maxtimes初始化参数值
4.1.9 ServletContext接口的使用
步骤:
实验1目标:作为域对象使用,实现Servlet间共享数据;
实验2目标:读取Web应用路径、资源文件;
实验3目标:获取Web应用程序的初始化参数
Ch0404-1的步骤:
ServletA:
- 创建ServletA,继承GeneriServlet
- 通过getServletContext()先拿到ServletContext
- 往context里写数据
- 通过res的getWriter()方法显示:ServletA: ser username
ServletB: - Service方法中,通过getServletContext()先拿到ServletContext
- 通过context调用getAttribute()方法去取数据,它的返回值类型为Object,我们需要的是字符串类型的,所以将它转换为字符串
- 用res的getWriter()方法在浏览器上显示ServletB: get username:,然后将得到的字符串输出出来。
ServletC: - 先拿到context
- Context调用removeAttribute(),将username给擦掉
- 在浏览器上显示ServletC: remove username
web.xml中配置ServletA、ServletB、ServletC的url
Ch0404-2的步骤:
11. 先拿到ServletContext
12. 调用getMajorVersion()和getMinorVersion()方法,得到主版本号和次版本号。将其输出,显示到页面上
13. 调用getMimeType()方法,得到文件类型,输出
14. 调用getServerInfo()方法,该方法返回服务器的名称和版本号,输出
15. 调用getServletContextName()方法,得到当前Web应用程序的上下文名称,也就是元素中path属性的斜杆(/)后面的内容,即’demo’
16. 调用getContextPath()方法,得到当前Web应用程序的上下文路径,也就是标签中path属性值,’/demo’
17. 调用getRealPath(hi.html)输出hi.html的真实路径(在电脑里的路径)
创建datal.prop文件放在web—WEB-INF目录下,用getResourceAsStream()方法获得里面的内容,读到输入流InputStream中
18. 新建一个Properties对象,解析输入流里的数据
19. 通过ps.getProperty()方法,用属性名,输出里面的内容
Ch0404-3的步骤:
20. 拿到一个ServletContext对象,一个PrintWriter对象
21. sout()是在控制台上输出,pw.write()是在浏览器上展示,getInitParam()获得原始数据
22. 在web.xml文件中配置参数和参数值### 代码
代码:
ch0404-1
public class ServletA extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
context.setAttribute("username","zhang3");
servletResponse.setContentType("text/html;");
servletResponse.getWriter().write("<h1>ServletA: set username</h1>");
}
}
public class ServletB extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
String userName = "" + context.getAttribute("username");
servletResponse.setContentType("text/html;");
servletResponse.getWriter().write("<h1>ServletB: get username:" + userName + "</h1>");
}
}
public class ServletC extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
context.removeAttribute("username");
servletResponse.setContentType("text/html;");
servletResponse.getWriter().write("<h1>ServletC: remove username </h1>");
}
}
<servlet>
<servlet-name>testA</servlet-name>
<servlet-class>test.mapping.ServletA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testA</servlet-name>
<url-pattern>/a</url-pattern>
<url-pattern>/set</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testB</servlet-name>
<servlet-class>test.mapping.ServletB</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testB</servlet-name>
<url-pattern>/b</url-pattern>
<url-pattern>/read</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>testC</servlet-name>
<servlet-class>test.mapping.ServletC</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testC</servlet-name>
<url-pattern>/c</url-pattern>
<url-pattern>/remove</url-pattern>
</servlet-mapping>
</web-app>
ch0404-2
@WebServlet("/x2")
public class ServletContext2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext sc = getServletContext();
int majorV = sc.getMajorVersion();
int minorV = sc.getMinorVersion();
PrintWriter pw = servletResponse.getWriter();
System.out.println("version:" + majorV + ",minorV:" + minorV);
pw.println("version:" + majorV + ",minorV:" + minorV);
pw.println("mime type( jpd):" + sc.getMimeType("a.jpg"));
pw.println("Server Info:" + sc.getServerInfo());
pw.println("Server getServletContextName:" + sc.getServletContextName());
pw.println("Server getContextPath:" + sc.getContextPath());
pw.println("Server realPath:" + sc.getRealPath("hi.html"));
InputStream in = sc.getResourceAsStream("/WEB-INF/classes/datal.prop");
Properties ps = new Properties();
ps.load(in);
in.close();
pw.println("read config, db.user:" + ps.getProperty("db.user"));
pw.println("read config, db.pwd:" + ps.getProperty("db.pwd"));
}
}
db.user = root
db.pwd = 123456
ch0404-3
@WebServlet("/x3")
public class ServletContext3 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
PrintWriter pw = servletResponse.getWriter();
System.out.println("school:" + context.getInitParameter("school"));
System.out.println("tel:" + context.getInitParameter("tel"));
pw.write("school:" + context.getInitParameter("school"));
pw.write("tel:" + context.getInitParameter("tel"));
}
}
<context-param>
<param-name>school</param-name>
<param-value>cqrk</param-value>
</context-param>
<context-param>
<param-name>tel</param-name>
<param-value>123456</param-value>
</context-param>
实验结果:
Ch0404-1的实验结果:
- ServletB最开始没有数据
2. 打开ServletA设置username
3. 再打开ServletB就可以看到username
4. 打开ServletC删除数据
5. 再看ServletB,发现数据空了
Ch0404-2运行结果:
Ch0404-3运行结果:
4.1.10.Servlet实践作业(页面及访问次数统计)
步骤:
- PageServlet
- 创建一个Web Project,命名为ch0405。在src目录下创建一个PageServlet.java文件,继承自GenericServlet,重写service()方法
- 定义一个int类型的对象pageCount,每次访问本页面,在service方法中pageCount++
- 通过ServletResponse输出pageCount的值
- SiteServlet
- 创建SiteServlet1和SiteServlet2,两个class文件
- 定义context,
- 利用context.getAttribute去获取appCounter对应的值(int类型),用data接受
- 如果取出来的data是空值,data=1;否则data+1
- 利用context.setAttribute将appCounter写进去
- 再用ServletReponse输出appCounter
- SiteServlet1、SiteServlet2、PageServlet都复制一份
代码:
@WebServlet("/PageServlet")
public class PagesServlet extends GenericServlet {
private int pageCount = 0;
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
pageCount++;
ServletContext context = getServletContext( );
Object data = context.getAttribute("appCounter");
if(data == null){
data = 1;
} else{
data = (Integer)data + 1;//强制转化,data类型改为int
}
context.setAttribute("appCounter", data);
servletResponse.getWriter().println("appCounter:" + data);
servletResponse.getWriter().println("PageCount = " + pageCount);
}
}
@WebServlet("/site1")
public class SiteServlet1 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
Object data = context.getAttribute("appCounter");
if(data == null){
data = 1;
} else{
data = (Integer)data + 1;//强制转化,data类型改为int
}
context.setAttribute("appCounter", data);
servletResponse.getWriter().println("appCounter:" + data);
}
}
public class SiteServlet2 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
ServletContext context = getServletContext();
Object data = context.getAttribute("appCounter");
if(data == null){
data = 1;
} else{
data = (Integer)data + 1;//强制转化,data类型改为int
}
context.setAttribute("appCounter", data);
servletResponse.getWriter().println("appCounter:" + data);
}
}
实验结果:
PageServlet:
Site页面更新appCounter
更新后的PageServlet: