(一)Servlet_JavaEE_学习笔记

一、Servlet简介

Servlet是sun公司提供的一门用于开发动态web资源的技术
Sun公司在其API中提供了一个servlet接口,用户若想开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:
编写一个Java类,实现servlet接口。
把开发好的Java类部署到web服务器中。

二、Servlet 编写

第一个Servlet的编写
动手练习,完成目标:利用Servlet向客户端输出”HelloSerlvet”,不借助IDEA,手动编写。
过程:
1.编写java文件
阅读Servlet API,解决两个问题:
输出hello servlet的java代码应该写在servlet的哪个方法内?
如何向IE浏览器输出数据?

import javax.servlet.*;

public class FirstServlet extends GenericServlet{
	public void service(ServletRequest req, ServletResponse res)
			throws ServletException, java.io.IOException{
				
		System.out.println("hello first servlet");
	}
}

2.编译,生成.class文件
在这里插入图片描述
报错原因:Javax.servlet相关的类不在jdk中。

如何能够编译通过呢?
通过 javac -classpath 指明一个jar包,来解决找不到相关包的问题。

servlet相关jar包哪个地方会有呢?
Tomcat的lib目录下servlet-api.jar
在这里插入图片描述
执行命令javac -classpath jar包的路径 java文件名,进行编译
在这里插入图片描述
3.如何运行
用java指令吗?
在这里插入图片描述
因为没有main方法,没法运行。再回想servlet定义。
A servlet is a small Java program that runs within a Web server
servlet它没有独立运行的能力,必须在服务器里面才能运行。

要想让实现servlet的相关代码运行起来,只能以发布应用的方式来实现,即让web服务器来调用servlet。首先要将编译后的class文件和tomcat服务器关联起来。

如何将class文件和tomcat关联?
标准JavaEE项目的目录结构。
在这里插入图片描述

这个结构是规定,记住。
在这里插入图片描述

接下来如何去访问该servlet呢?如何让servlet运行?
任何在WEB-INF目录下的文件都不可以直接被浏览器访问到,所以需要配置一个映射。
映射一个关系,比如访问/serv,那么让tomcat去运行与/serv相关联的一个servlet。告诉tomcat,你访问/serv,那么就是希望我去调用这个servlet的service方法
在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_3_1.xsd"
  version="3.1"
  metadata-complete="true">
	
	<!--重点关注部分: -->
    <servlet>
        <servlet-name>first</servlet-name>
        <servlet-class>FirstServlet</servlet-class> //类名
    </servlet>

    <servlet-mapping>
        <servlet-name>first</servlet-name>
        <url-pattern>/serv</url-pattern> //url-pattern 将应用ROOT和servlet接口的实现类联系起来,访问/serv,就能找到FirstServlet类,进而调用类中的方法
    </servlet-mapping>
</web-app>

就是配置一个映射关系,当访问/serv的时候,那么这个时候tomcat就去做一件事情,找到与/serv相对应的FirstServlet,反射实例化对象,调用该servlet的service方法。
url-pattern:servlet-class

访问servlet?
Localhost:8080/serv,这里应用名默认为ROOT,可以省略
在这里插入图片描述
如果你想让内容输出到浏览器正文,内容应当写入到响应报文的响应体中。
servletRequest和servletResponse其实就是代表了请求报文和响应报文。
那么response里面有哪个API是往响应体里面写入数据的呢?
Response.getWriter().println()

Localhost:8080/servlet/serv
在访问某个servlet的时候,一定要记得看一下它的应用名是谁。

执行过程总结:

  1. 在浏览器里面输入localhost:8080/servlet/serv,浏览器会帮助你构建一个http请求报文
  2. 请求报文到达主机之后,被connector获取到,会将请求报文封装成request对象,同时还给你一个response,用来填充数据
  3. 这两个对象被传给engine,挑选哪个host来处理
  4. host挑选哪个Context来处理,这两个对象交给指定的Context
  5. Context拿到/serv,根据/serv找到对应的类后,实例化对象,调用service方法,执行结束,返回
  6. 返回到connector,读取response里面的内容,按照一定的格式组装成响应报文,发送出去
    在这里插入图片描述
    Servlet的运行过程:
    Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
    1.Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。如果是,则直接执行第④步,否则,执行第②步。
    2.装载并创建该Servlet的一个实例对象。
    3.调用Servlet实例对象的init()方法。
    4.tomcat创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
    5.WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

三、其他开发servlet的方式

Servlet接口实现类:
Servlet接口SUN公司定义了两个默认实现类,分别为:GenericServlet、HttpServlet。

HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。

**HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。**因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

  • protected void doGet(HttpServletRequest req, HttpServletResponse
    resp)
    Called by the server (via the service method) to allow a servlet to handle a GET request.
    由服务器调用(通过service方法),以允许servlet处理GET请求。
  • protected void doPost(HttpServletRequest req, HttpServletResponse
    resp)
    Called by the server (via the service method) to allow a servlet to handle a POST request.
    由服务器调用(通过service方法)以允许servlet处理POST请求。

1.继承HttpServlet
这里我们使用IDEA进行项目的开发,以下是关于IDEA的一些使用。

  • 新建web项目
    在这里插入图片描述
    在这里插入图片描述
  • 点击此处进行配置
    在这里插入图片描述
    在这里插入图片描述
    如果下面的Application context是 / ,则表示应用名是ROOT,即默认的,当在浏览器访问时输入url时可以省略应用名的字段。
    在这里插入图片描述
  • 点击Debug(初学推荐)启动项目。
    在这里插入图片描述
  • 在浏览器输入url,就会访问到根目录下的index.jsp
    在这里插入图片描述
  • 再次点击Debug按钮,会出现如下图所示弹窗。
    在这里插入图片描述
    Update resources 是 更新静态资源文件
    Update classes and resources 是 更新class文件及静态资源文件
    Redeploy 重新部署当前应用
    Restart server 重启Tomcat

    如果只是更改了项目中的静态资源文件,选1;如果更改了java文件,选2;如果更改了web.xml,选3。第三种大部分情况下可以满足需求,第四种对电脑性能要求高。

A subclass of HttpServlet must override at least one method, usually one of these:
doGet, if the servlet supports HTTP GET requests
doPost, for HTTP POST requests
doPut, for HTTP PUT requests
doDelete, for HTTP DELETE requests
init and destroy, to manage resources that are held for the life of the servlet
getServletInfo, which the servlet uses to provide information about itself

对于get和post方法的区别,仅是语义上的区别。
Web.xml配置和上面手动实现相同。
如果支持get方法,那么就重写doGet
如果支持post方法,那么就重写doPost

public class ThirdServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doGet(req, resp);
        resp.getWriter().println("doget method");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //super.doPost(req, resp);
        resp.getWriter().println("dopost method");
    }
}

web.xml

<servlet>
        <servlet-name>third</servlet-name>
        <servlet-class>com.cskaoyan.servlet.ThirdServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>third</servlet-name>
        <url-pattern>/third</url-pattern>
    </servlet-mapping>

在这里插入图片描述
问题:为什么继承GenericServlet需要实现service方法,而继承HttpServlet不需要?
因为HttpServlet已经对这个抽象的service方法做了实现。

2.继承HttpServlet,使用注解进行映射
使用注解和使用web.xml方式完全等效。在实际开发中使用一种方式即可。

@WebServlet("/fourth")
public class FourthServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("fourth servlet");
    }
}

在这里插入图片描述

3.简便方式
这种方式直接由IDEA帮助我们实现。
在这里插入图片描述

四、IDEA和Tomcat的关联方式

IDEA是如何让程序运行起来的呢?其实就是IDEA在Tomcat中部署了一个应用。
部署应用的方式?两种。直接部署和虚拟映射。
但是我们去conf/server.xml(虚拟映射)和webapps(直接部署)目录下看发现都没有。
怎么找呢?
去IDEA中找:
在这里插入图片描述
上面的两个目录会打印一些运行日志,查看错误日志需要这两个目录都看。
我们看一下CATALINA_BASE所指示的目录:
在这里插入图片描述
我们发现CATALINA_BASE目录的结构和Tomcat的安装目录结构很相似。为什么会这样呢?
IDEA复制了tomcat的一些核心配置文件,然后利用这些配置文件重新开启一个新的tomcat,利用这个tomcat来部署我们的应用。而不是直接在Tomcat中进行修改,这是IDEA的高明之处。
在这里插入图片描述
在其中的conf目录下有一个应用名.xml文件,docBase指向的就是你的部署根目录。
打开部署根目录去看一下:
在这里插入图片描述
总结:IDEA会复制tomcat的配置文件,然后到某一个目录下,在该目录下利用复制的配置文件重新开启一个新的tomcat来虚拟映射部署我们的应用。
但是如果你细心的话,你会发现,我们的开发目录和项目部署根目录不是同一个目录。
在这里插入图片描述
那么开发目录和部署目录之间有什么关联呢?
开发目录和部署目录不是一个目录。
开发目录里面存放的是java文件,这些文件编译之后,会按照某个规则,将class文件以及web相关联的文件(web.xml、index.jsp等)全部复制到部署根目录去。

规则在哪里体现出来的呢?
在这里插入图片描述
开发目录的web目录对应将来的部署根目录,src中的java文件会经过编译后放到classes文件下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
最常见的一个问题:在开发web目录下新建了一个1.html,然后访问显示404.
注意:凡是要以部署根目录里面的内容为准。
idea没有正常将开发web目录里面的文件同步到部署根目录,挺常见。
1.先重新部署一下试试
2.不行的话:
在这里插入图片描述
重新部署。
3.如果还是不行,可以直接把部署根目录里面的文件全部删了,然后再次执行2,重新部署

五、Servlet 生命周期

init:初次访问当前servlet时会被调用,再次访问不会被调用。
service:每次请求到来,都会被调用。
destroy:应用被卸载或者服务器关闭时被调用。

@WebServlet(value = "/Life")
public class LifeCycleServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        System.out.println("init");
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

在这里插入图片描述
其中有一个比较特殊的东西,init默认是在当前servlet第一次被访问的时候执行,但是可以通过设置一个load-on-startup为一个非负数,可以让其随着应用的加载而被执行。
在这里插入图片描述
或者通过web.xml
在这里插入图片描述
这样做的意义有哪些?
预先做一些初始化操作,比如查询数据库等。放在init方法里面。

六、url-patterns

1.url-patterns和servlet的对应关系
一个servlet可以配置多个url-pattern吗?
允许的
在这里插入图片描述
多个servlet可以配置同一个url-pattern吗?
不可以,会报错。报错信息一定要会找。
名为 [.url.UrlServlet2]和 [.url.UrlServlet] 的servlet不能映射为一个url模式(url-pattern) [/url1]。

总结:可以通过多个url-patterns找到同一个实现类,而不能通过一个url-patterns找到多个实现类。

url-pattern的写法有哪些?必须以/开头吗?
写法只有两种。一种/开头,另一种*.后缀。比如*.html。如果不是这两种写法,会报错
Caused by: java.lang.IllegalArgumentException: Invalid [Servlet1] in servlet mapping

2.url-patterns的优先级
Servlet1 映射到 /abc/*
Servlet2 映射到 /*
Servlet3 映射到 /abc
Servlet4 映射到 *.do

当请求URL为“/abc/a.html”,“/abc/”和“/ * ”都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/abc”时,“/abc” /都匹配,哪个servlet响应
Servlet引擎将调用Servlet3。
当请求URL为“/abc/a.do”时,“/abc/
”和“
.do”和/都匹配,哪个servlet响应
Servlet引擎将调用Servlet1。
当请求URL为“/a.do”时,“/
”和“.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。
当请求URL为“/xxx/yyy/a.do”时,“/
”和“*.do”都匹配,哪个servlet响应
Servlet引擎将调用Servlet2。

规律:

  1. /开头的优先级始终要高于*.后缀
  2. 匹配程度越高,越优先执行

3.两个特殊的url-patterns
一个/* 另外一个/
在这里插入图片描述
项目里设置了两个特殊的url-pattern,然后访问web根目录下面的index.jsp以及1.html发现此时均无法访问到,显示的均是/* servlet里面的内容。
接下来,将/*的servlet注释,只保留/
发现jsp页面可以正常显示,但是html页面仍然无法正常显示(显示的是/里面的内容)
在这里插入图片描述
在这里插入图片描述
从上面图片,可以得出什么结论?
平时访问的jsp页面,实际上是访问的是一个servlet。
比如localhost:8080/index.jsp,实际访问的是一个servlet,servlet做了一些事情,最终显示了页面。

问题1:为什么设置了/ *以后,jsp无法正常显示?
/ * 的优先级高于 * .jsp。因为 / * 没有做一些事情,所以最终无法显示出页面。

问题2:把 / * 注释,只保留/,jsp可以正常显示,但是html仍然无法正常显示?
/是一个比较特殊的url-pattern,DefaultServlet。
缺省servlet:看你有没有servlet可以处理你的这个请求,如果没有,缺省给你用。

任何一个请求到来,都应当有一个servlet来做出响应。但是如果你的应用中没有配置某一个请求的url-pattern,那么这个时候tomcat服务器会调用自身提供的缺省servlet来帮助你处理该请求。

比如:应用中没有配置任何的url-pattern映射,当访问/1.html时,发现当前应用内没有任何的servlet可以处理该请求,但是也不能让这个请求无人响应,tomcat会调用自身的缺省servlet来处理该请求,逻辑也非常简单:
到对应的目录中去找到对应的文件,如果找到,则以流的形式写出去;如果找不到,则404。(404也是一种回应)
当你自己设置了一个url-pattern,比如/1.html,再次访问/1.html,发现有servlet可以处理该请求。

总结:设置了/ * , /,jsp页面以及html页面均无法正常显示。/ * 的优先级是 比较高的,高于jsp的 * .jsp,所以显示的是 / * ,
接下来,/ * 注释,jsp可以交给*.jsp来处理,html到来,只能交给缺省servlet来处理。如果你的应用中,已经在注解中配置类url-patterns,tomcat会认为你有了一个更好的实现方式,tomcat自身提供的缺省servlet就不会给你使用了,而是使用你自身的/。
在这里插入图片描述

七、ServletConfig

可以获取某个servlet一些初始化的配置参数
步骤1:配置参数
在这里插入图片描述
步骤2:获取参数
在这里插入图片描述

八、ServletContext

1.配置全局初始化参数:直接在web-app节点下设置即可,不需要写在servlet节点下。
在这里插入图片描述
2.获取全局性参数:
String getInitParameter(String name)
Returns a String containing the value of the named context-wide initialization parameter, or null if the parameter does not exist.
返回一个字符串,其中包含命名的Context范围的初始化参数的值;如果该参数不存在,则返回null。

@WebServlet("/context1")
public class ContextServlet1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        String name = servletContext.getInitParameter("name");
        System.out.println(name);
    }
}
@WebServlet("/context2")
public class ContextServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        String name = servletContext.getInitParameter("name");
        System.out.println(name);

    }
}

3.共享数据的场所(setAttribute/getAttribute)
当前应用下的两个servlet之间如果想要共享数据,怎么办?

Object getAttribute(String name)
Returns the servlet container attribute with the given name, or null if there is no attribute by that name.
返回具有给定名称的servlet容器属性;如果该名称没有属性,则返回null。

void setAttribute(String name, Object object)
Binds an object to a given attribute name in this servlet context.
在此Servlet的Context中将对象绑定到给定的属性名称。

  1. 先设置数据
@WebServlet("/domain1")
public class ContextDomainServlet1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        //JDBC  商场的商品信息  List<Type>  电器  衣服  化妆品
        servletContext.setAttribute("name", "iphone");
        //servletContext.removeAttribute("name");
    }
}
  1. 其他servlet去获取数据
@WebServlet("/domain2")
public class ContextDomainServlet2 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = getServletContext();
        String name = (String) servletContext.getAttribute("name");
        System.out.println(name);
    }
}

九、获取EE项目的绝对路径(getRealPath())

String getRealPath(String path)
Returns a String containing the real path for a given virtual path.
返回一个字符串,其中包含给定虚拟路径的真实路径(真实路径就是在部署根目录中的路径)。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //获取web根目录下的1.html的file信息  流信息
    File file = new File("1.html");
    System.out.println(file.getAbsolutePath());
    System.out.println(file.exists());
    // $TOMCAT_HOME/bin/1.html????为啥会到这个目录下面
    //EE项目:没有main方法,你写的代码只是供tomcat调用罢了
    //file的相对路径相对的是谁?相对的是在哪个目录下调用jvm虚拟机
    //获取文件的话,还是希望放在web根目录下:
    //1.bin目录下不可以存放相同名称的文件,不同应用产生的相同文件会覆盖
    //2.很不方便打包
    //输入空字符串相当于已经定位到web根目录了
    //接下来,如果想获取一个文件的file信息,只需要指明它和根目录的相对路径即可
    String realPath = getServletContext().getRealPath("");
    System.out.println(realPath);
    String path1 = getServletContext().getRealPath("1.html");
    boolean exists = new File(path1).exists();
    System.out.println(exists);
    //如果你想获取WEB-INF下面的1.txt,怎么获取
    //能不能获取到?????可以。
    //WEB-INF对于服务器来说,就是一个普通的文件夹
    //该目录主要是用来拦截浏览器直接访问的
    //WEB-INF目录用来拦截浏览器直接访问,但是防不住服务器有内鬼,将内容主动暴露出去
    String realPath1 = getServletContext().getRealPath("WEB-INF/1.txt");
    boolean exists1 = new File(realPath1).exists();
    System.out.println(exists1);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值