欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

学习JAVAWEB(四)——SERVLET

程序员文章站 2022-06-03 09:58:11
...

前言:

承接前面的内容来学习JavaWeb中的Servlet

 

 

 

 

 


什么是Servlet

  1. Servlet是JavaEE规范之一。规范,就是接口。
  2. Servlet是JavaWeb三大组件之一。(三大组件:Servlet程序、Filter过滤器、Listener监听器)
  3. Servlet是运行在服务器上的一个Java小程序,它可以接收客户端发送过来的请求,并相应数据给客户端。

学习JAVAWEB(四)——SERVLET

 


创建Servlet程序

  1. 编写一个类去实现Servlet接口
  2. 实现Service方法,处理请求并相应数据
  3. 到web.xml中去配置servlet程序的访问地址

在上次的项目下,在包下面新建一个Java类,继承自Servlet,按下Alt+Insert来实现接口的几个方法。

public class HelloServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    //services方法是专门用来处理请求和响应的
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet!");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

然后我们来修改WEB-INF/web.xml,添加内容:

    <!--servlet标签给Tomcat配置servlet程序-->
    <servlet>
        <!--给servlet程序起一个别名(一般是类名)-->
        <servlet-name>HelloServlet</servlet-name>
        <!--程序的全类名-->
        <servlet-class>com.javaweb.test.HelloServlet</servlet-class>
    </servlet>
    <!--给servlet程序配置访问地址-->
    <servlet-mapping>
        <!--告诉服务器当前配置的地址给哪个Servlet程序使用-->
        <servlet-name>HelloServlet</servlet-name>
        <!--配置访问地址-->
        <!--
            / 斜杠在服务器解析的时候,表示地址为:http://ip:port/工程路径
            /Hello 表示地址为 http://ip:port/工程路径/Hello
        -->
        <url-pattern>/Hello</url-pattern>
    </servlet-mapping>

最后,我们启动程序,在自动打开的页面的url后加上 Hello访问,然后在IDEA控制台中,就可以看到输出Hello Servlet!

尚硅谷的这个流程图总结的非常好,我们来看看:

学习JAVAWEB(四)——SERVLET


Servlet 学习

Servlet生命周期

在第一次访问时(创建实例)会调用:

  • Servlet 构造器方法
  • init 初始化方法

在每次访问都会调用

  •  service 方法

在 web 工程停止的时候调用

  • destroy 方法(释放内存)

 

Servlet 请求分发处理

我们需要判断请求的不同类型来做不同的处理

    //services方法是专门用来处理请求和响应的
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) 
                                          throws ServletException, IOException {
        System.out.println("Hello Servlet!");
        //类型转换(因为它有GetMethod()方法)
        HttpServletRequest httpServletRequest= (HttpServletRequest) servletRequest;
        String method=httpServletRequest.getMethod();
        if("GET".equals(method)){
            doGet();
        }else if("POST".equals(method)){
            doPost();
        }
    }

    public void doGet(){
        System.out.println("get");
    }
    public void doPost(){
        System.out.println("post");
    }

我们可以写一个简单的页面来测试:

<body bgcolor="#f4a460">
    <form action="http://localhost:8080/web_war_exploded/Hello" method="post">
        <input type="submit" />
    </form>
</body>

学习JAVAWEB(四)——SERVLET

 

通过继承HttpServlet类实现

一般在实际项目开发中,都是使用继承 HttpServlet 类的方法去实现Servlet程序。

  1. 编写一个类去继承HttpServlet类
  2. 根据业务需要重写doGet或doPost方法
  3. 到web.xml中的配置Servlet程序的访问地址

我们来重写一个类来做示例,重创建一个 HelloServlet2,并且让它继承自 HttpServlet 。

在HttpServlet中,已经自动帮助我们根据请求方式分发好了get请求处理和post请求处理。

public class HelloServlet2 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("HelloServlet2的doget");
    }

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

然后我们去web.xml中配置,加上

    <servlet>
        <servlet-name>HelloServlet2</servlet-name>
        <servlet-class>com.javaweb.test.HelloServlet2</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HelloServlet2</servlet-name>
        <url-pattern>/Hello2</url-pattern>
    </servlet-mapping>

然后将Test.html中表单的发送地址发送给Hello2,然后测试一下,和上面效果一样。

 

使用IDEA直接生成

在需要生成Servlet文件的包那里,右击,下面有个创造Servlet文件,点击即可。

学习JAVAWEB(四)——SERVLET

非常方便。

它会在对应的web.xml中生成<Servlet></Servlet>,你再给它写一下servlet-mapping即可

    <servlet-mapping>
        <servlet-name>HelloServlet3</servlet-name>
        <url-pattern>/Hello3</url-pattern>
    </servlet-mapping>

 

Servlet继承体系

学习JAVAWEB(四)——SERVLET

ServletConfig类

基本了解

我们学一下另一个东西换换脑——ServletConfig类

ServletConfig类是Servlet程序的配置信息类。

三大作用

  1. 可以获取Servlet程序的别名——servlet-name的值
  2. 获取初始化参数 init-param
  3. 获取 ServletContext 对象

 

回头实现Servlet接口的那个类——HelloServlet,看看初始化的方法 init,我们就会发现init的参数就是一个ServletConfig对象。

我们首先可以修改xml配置文件来添加初始化参数,以我们的第一个类为例:

    <!--servlet标签给Tomcat配置servlet程序-->
    <servlet>
        <!--给servlet程序起一个别名(一般是类名)-->
        <servlet-name>HelloServlet</servlet-name>
        <!--程序的全类名-->
        <servlet-class>com.javaweb.test.HelloServlet</servlet-class>
        <!--init-param是初始化参数-->
        <init-param>
            <!--参数名-->
            <param-name>name</param-name>
            <!--参数值-->
            <param-value>root</param-value>
        </init-param>
        <init-param>
            <!--参数名-->
            <param-name>url</param-name>
            <!--参数值-->
            <param-value>is-hash.com</param-value>
        </init-param>
    </servlet>

然后,修改类中的init方法:

    public void init(ServletConfig servletConfig) throws ServletException {
        System.out.println("HelloServlet程序的别名是"+servletConfig.getServletName());
        System.out.println("初始化参数username的值是"+servletConfig.getInitParameter("name"));
        System.out.println("初始化参数url的值是"+servletConfig.getInitParameter("url"));
        System.out.println(servletConfig.getServletContext());
    }

然后,启动项目(http://localhost:8080/web_war_exploded/Hello)就会看到打印:

HelloServlet程序的别名是HelloServlet
初始化参数username的值是root
初始化参数url的值是is-hash.com
aaa@qq.com

这个ServletContext我们后面会介绍。

 

补充:

Servlet程序和ServletConfig对象都是由Tomcat负责创建,我们负责使用。

Servlet程序默认是第一次访问的时候创建,ServletConfig是每个Servlet程序创建时就创建一个对应的ServletConfig对象。

不止init,在其他方法中也可以得到ServletConfig对象。

例如我们的HelloServlet2中,在doGet方法内可以使用如下命令得到HelloServlet2对应的ServletConfig对象:

        ServletConfig servletConfig=getServletConfig();

一定要注意:这里得到的ServletConfig一定是对应的自己的那个Servlet类的ServletConfig。

还有一点,如果在子类(HttpServlet )中调用init方法,一定要加上下面的语句:

super.init(config);

原因很简单,在父类(GenericServlet)的init方法中,定义了这样:

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

如果重写init而不执行父类的init,意味着父类的init被完全覆盖,也就不会将config保存给自己的属性config,这样得到的config就不能使用,是一个空指针。

 

ServletContext类

基础了解:

上面我们出现了一个ServletContext对象,那么这个是什么呢?

ServletContext也是一个接口,他表示Servlet上下文对象。

一个web工程只有一个ServletContext对象实例。

ServletContext对象是在Web工程启动时创建,在停止时销毁(重新部署就会销毁这个对象),而只要你有这个对象没被销毁,那么可以工程的任何地方得到这个对象。

ServletContext对象是一个域对象

域对象:是可以像Map一样存取数据的对象。

这里的域指的是存取数据的操作范围(这里是整个web工程)。

我们来看看他和Map对象的对比:

  存数据 取数据 删除数据
Map put get remove()
域对象 setAttribute() getAttribute() removeAttribu

ServletContext类的四个作用

  1. 获取web.xml中配置的上下文参数
  2. 获取当前的工程路径(/工程名)
  3. 获取工程部署后在服务器磁盘上的绝对路径
  4. 像Map一样存储数据

 

我们来新建一个Servlet文件来做实验,记得配置好xml文件:

    <servlet-mapping>
        <servlet-name>ContextServlet</servlet-name>
        <url-pattern>/Context</url-pattern>
    </servlet-mapping>

然后创建一个 “上下文参数” 来做示例,直接在web.xml中添加:

    <context-param>
        <param-name>Context</param-name>
        <param-value>ContextValue</param-value>
    </context-param>

下面是ContextServlet.java的内容:

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
                                           throws ServletException, IOException {
        ServletContext context=getServletConfig().getServletContext();
        //根据键得到Context-param上下文参数的值
        //别被getInitParameter这个误导,他与一个Servlet对象的Init-param是两回事
        String username=context.getInitParameter("Context");
        System.out.println("上下文参数Context的值是:"+username);
        //得到当前路径
        System.out.println("当前工程路径:"+context.getContextPath());
        //得到主机中的具体路径
        /*
        这里解释一下为什么是"/",http://ip:port/工程名,"/"就是
        映射到IDEA代码的web目录(目录名web,不是模块名)
        */
        System.out.println("工程部署的路径是"+context.getRealPath("/"));
    }

直接访问(Get请求)/工程名/Context,控制台输出:

上下文参数Context的值是:ContextValue
当前工程路径:/web_war_exploded
工程部署的路径是F:\Idea的平时作品\JavaWeb\out\artifacts\web_war_exploded\

下面我们再来验证第四个功能,像Map一样存储数据:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取ServletContext对象
        ServletContext context=getServletContext();
        context.setAttribute("key1","value1");
        System.out.println("Context1 key1的值是:"+context.getAttribute("key1"));
    }
输出:
Context1 key1的值是:value1

 


HTTP

什么是http协议

又回到基础问题了

什么是协议?

协议,是指双方或多方相互约定好,大家都需要遵守的规则,叫协议。

所谓HTTP协议,就是指客户端和服务器之间通信时发送的数据,需要遵守的规则,叫HTTP协议。

Http协议中的数据又叫报文

 

GET请求

  • 请求行
    • 请求的方式:GET
    • 请求的资源路径(+?+请求参数)
    • 请求的协议的版本号:HTTP/1.1
  • 请求头
    • key-value组成,不同的键值对表示不同的含义

学习JAVAWEB(四)——SERVLET

POST请求

  • 请求行
    • 请求的方式:POST
    • 请求的资源路径(+?+请求参数)
    • 请求的协议的版本号:HTTP/1.1
  • 请求头
    • key-value组成,不同的键值对表示不同的含义
  • 请求体:就是发送给服务器的数据

学习JAVAWEB(四)——SERVLET

常用请求头

  1. Accept:表示客户端可以接受的数据类型
  2. Accept-Languege:表示客户端可以接收的语言类型
  3. User-Agent:表示客户端浏览器的信息
  4. Host:表示请求时的服务器ip和端口号

 

常见请求方式

GET请求

  1. form标签 method=“get”
  2. a 标签
  3. link标签引入css
  4. Script标签引入js文件
  5. img标签引入图片
  6. iframe引入html页面
  7. 在浏览器输入url访问

POST请求

  1. form标签 method=“post”

 

响应的HTTP协议介绍

  • 响应行
    • 响应的协议和版本号
    • 响应状态码
    • 响应状态描述符
  • 响应头
    • key-value组成,不同的键值对表示不同的含义
  • 响应体:就是回传给客户端的数据

学习JAVAWEB(四)——SERVLET

常见HTTP响应码:

  1. 200:表示请求成功
  2. 302:表示请求重定向
  3. 404:表示请求服务器已经收到了,但是你要的数据不存在(找不到页面)
  4. 500:表示服务器已经收到请求,但是服务器内部错误(代码出问题)

 

MIME类型说明

MIME是HTTP协议中数据类型。

MIME的英文全称是“Multipurpose Internet Mail Extensions”(多功能Internet邮件扩充服务)。

MIME类型的格式是“大类型/小类型”,并与某一种文件的扩展名相对应。

学习JAVAWEB(四)——SERVLET

 


常见知识点:

HttpServletRequest

每次有请求进入Tomcat服务器,Tomcat服务器就会把请求过来的Http协议信息封装到Request对象中。 然后传递到service方法(doGet和doPost)中给我们使用。我们可以通过HttpServletRequest对象,获取到所有请求的信息。

我们可以在doGet/doPost里面得到这个参数

常用方法:

  1. getRequestRUI( ):获取请求的资源路径
  2. getRequestURL():获取请求的统一资源定位符(绝对路径)
  3. getRemoteHost( ):获取客户端的ip地址
  4. getHeader( ):获取请求头
  5. getParameter( ):获取请求的参数
  6. getParameterValues( ):获取请求的参数(多个值的时候使用)
  7. getMethod( ):获取请求的方式GET或者POST
  8. setAttribute(key,value):设置域数据
  9. getAttribute(key):获取域数据
  10. getRequestDispatcher():获取请求转换对象

 

如何获取客户端请求的参数

利用好API方法即可,示例:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //改变编码方式需要在获取参数前调用
        request.setCharacterEncoding("UTF-8");
        //通过name基本属性来得到value
        String username=request.getParameter("username");
        String password=request.getParameter("password");
        String[] hobby=request.getParameterValues("hobby");

        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.asList(hobby));
    }

request.setCharacterEncoding("UTF-8");常常用来解决POST请求中文乱码问题。

 

请求的转发

请求转发是指,服务器收到请求之后,从一次资源跳转到另一个资源的操作叫做请求转发。

下面来看看示例:

ContextServlet.java:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username=request.getParameter("username");
    System.out.println("ContextServlet得到用户名:"+username);
    //设置一个域变量
    request.setAttribute("key","first");
    //请求转发必须要以斜杠打头
    //斜杠代表地址是:http://ip:port/工程名/
    //Dispatcher可以理解为调度
    RequestDispatcher requestDispatcher
            =request.getRequestDispatcher("/Hello3");
    //进行请求转发
    requestDispatcher.forward(request,response);
}

HelloServlet3.java

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username=request.getParameter("username");
        System.out.println("HelloServlet3得到用户名:"+username);
        //查看Context是否有记录域变量
        Object key1= request.getAttribute("key");
        System.out.println("ContextServlet是否有记录"+key1);
        //处理自己的业务
        System.out.println("HelloServlet3 处理自己的业务");
    }

然后我们使用一个表单随便输入点东西然后提交给/Context(映射到ContextServlet类)

控制台打印:

ContextServlet得到用户名:奥术大师多
HelloServlet3得到用户名:奥术大师多
ContextServlet是否有记录first
HelloServlet3 处理自己的业务

 

base标签

如果利用请求转发去转发一个页面,由于路径问题可能会存在这样的一种情况

学习JAVAWEB(四)——SERVLET

解决这个问题,就可以使用base标签

base标签可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转

示例:

学习JAVAWEB(四)——SERVLET

这个就设置好了本页面中所有相对路径的参考地址

 

 

HttpServletResponse类

HttpServletResponse类的作用

HttpServletResponse类和HttpServletRequest类一样。每次请求进来,Tomcat服务器都会创建一个Response对象传递给Servlet程序去使用。

我们如果需要设置返回给客户端的信息,就可以通过 HttpServletResponse 对象来设置。

 

两个输出流的说明

  • 字节流–getOutputStream():常用于下载(传递二进制数据)
  • 字符流–getWriter():常用于回传字符串(常用)

两个流同时只能使用一个。

 

如何往客户端回传字符数据

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //得到字符流
        PrintWriter writer=response.getWriter();
        writer.println("response content");
    }

然后访问/Context,映射到这个类里面,客户端页面就会显示 response content

这里注意一下,直接这样使用是不能回传中文,如果你通过流输出中文,会显示成问号,我们可以打印回传字符集看一下:

System.out.println(response.getCharacterEncoding());

打印:ISO-8859-1

字符集不支持中文

我们可以尝试设置一下字符集:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        //得到字符流
        PrintWriter writer=response.getWriter();
        writer.println("有意思");
    }

再做测试我们会发现,客户端浏览器已经不现实问号了,但是显示了乱码。

这是因为我们只是把服务器端的字符集改变了,浏览器的字符集与服务器端的字符集不统一,所以会造成这个情况。

我们可以在客户端浏览器上去改,但是这样很不现实,因为以后项目展示出来不可能让客户一个一个去改。

所以我们可以直接在服务器端下手,添加响应头,这样浏览器就可以按照UTF-8来显示了:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        //添加响应头,设置浏览器也使用UTF-8字符集
        response.setHeader("Content-Type","text/html;charset=UTF-8");
        //得到字符流
        PrintWriter writer=response.getWriter();
        writer.println("有意思");
    }

或者,你可以直接设置内容类型:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //它会设置服务器和客户端都使用UTF-8字符集,同时设置响应头
        //此方法一定要在获取流对象之前设置才有效!
        response.setContentType("text/html;charset=UTF-8");
        //得到字符流
        PrintWriter writer=response.getWriter();
        writer.println("有意思");
    }

响应头信息:

Content-Length: 11
Content-Type: text/html;charset=UTF-8
Date: Fri, 24 Apr 2020 11:25:56 GMT
Server: Apache-Coyote/1.1

 

 

请求重定向

第一种方法

请求重定向,是指客户端给服务器发请求,然后服务器告诉客户端说。我给你一些新地址,你去新的地址访问(因为之前的地址可能已经被废弃)。

学习JAVAWEB(四)——SERVLET

我们来测试:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("经过Context文件");
        //设置响应状态码302,表示重定向
        response.setStatus(302);
        //设置响应头,说明新的地址在哪里
        response.setHeader("Location","http://127.0.0.1:8080/web_war_exploded/Hello3");
    }

在Hello3对应的那个类里面写上:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("经过Hello3");
    }

然后我们访问Context,控制台就会输出:

经过Context文件
经过Hello3

请求转发和请求重定向可能很像,但其实很不一样:

本质区别:请求转发只是发了一次请求,请求重定向发了两次请求。

  • 地址栏
    • 请求转发:地址栏还是当初请求的地址栏;
    • 请求重定向:地址栏不会是初次的地址栏,地址栏最后一次相应的地址栏。
  • request对象
    • 请求转发:在最终的servlet中,request对象和中转的request对象是同一个对象;
    • 请求重定向:在最终的servlet中,request对象和中转的request对象不是同一个对象。
  • /的意义:
    • /代表当前web应用的根目录http://localhost:8080/servlet02,是当前web的根目录;
    • 请求重定向:/代表当前web站点的根目录http://localhost:8080是当前web站点。
  • 范围
    • 请求转发:只能转到当前web资源;
    • 请求重定向:可以重定向到外部资源。

302请求重定向的特点:

  1. 浏览器地址栏会发生变化
  2. 两次请求
  3. 不共享Request域中数据
  4. 不能访问WEB-INF下的资源
  5. 可以访问工程外的资源

第二种方法

一行代码搞定:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("经过Context文件");
        response.sendRedirect("http://127.0.0.1:8080/web_war_exploded/Hello3");
    }

 

 


补充:

JavaEE项目的三层架构

学习JAVAWEB(四)——SERVLET

分层是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护与升级。

分层常常对应包:

  •  web层
    • com.atluoluo.web/servlet/controller
  • service层
    • com.atluoluo.services:Service 接口包
    • com.atluoluo.services.impl:Service 接口实现类
  • dao持久层
    • com.atluoluo.dao:Dao接口包
    • com.atluoluo.dao.impl:Dao接口实现类
  • 实体bean对象
    • com.atluoluo.pojo/entity/domain/bean:JavaBean类
  • 测试包
    • com.atluoluo.test/junit
  • 工具类
    • com.atluoluo.utils

 

 

 

 


 

 

商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢

相关标签: javaweb servlet