2.servlet相关

Servlet

1 servlet技术初涉

1.1 什么是Servlet

  • Servlet是javaEE规范之一,规范就是接口。
  • Servlet是javaWeb的三大组件之一。三大组件分别是Servlet程序,Filter过滤器,Listener监听器。
  • Servlet是运行在服务器上的一个java小程序,它可以接收客户端发过来的请求,并响应数据给客户端。

1.2 手动实现Servlet程序

1)编写一个类去实现Servlet接口。

2)实现service方法,处理请求,并响应数据。

package com.atguigu.servlet;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;

/**
 * @author 龍
 */
public class HelloServlet implements Servlet {
    public HelloServlet() {
        System.out.println("1.构造器方法。");
    }

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        
    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * service:专门用来处理请求和响应的
     * @param servletRequest
     * @param servletResponse
     * @throws ServletException
     * @throws IOException
     */
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("3.service方法");
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String method = request.getMethod();
        System.out.println("http的请求方式为:"+method);
        if("GET".equalsIgnoreCase(method)){
            doGet();
        }else if("POST".equalsIgnoreCase(method)){
            doPost();
        }

    }
    public void doGet(){
        System.out.println("doGet的方法");
    }
    public void doPost(){
        System.out.println("doPost的方法");
    }

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

    @Override
    public void destroy() {
        System.out.println("4.销毁的方法");
    }
}

3)到web.xml中去配置servlet程序以及访问地址。


<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>HelloServletservlet-name>
    <servlet-class>com.atguigu.servlet.HelloServletservlet-class>
servlet>

<servlet-mapping>
    
    <servlet-name>HelloServletservlet-name>
    
    <url-pattern>/helloServleturl-pattern>  
    
servlet-mapping>
web-app>

常见错误

1)url-pattern中配置的路径没有以斜杠开头(invalid:无效的)。
2.servlet相关_第1张图片

2)servlet-name配置的值不存在。
2.servlet相关_第2张图片

1.3 访问的原理解析

2.servlet相关_第3张图片

1.4 Servlet的生命周期

  1. 对象的创建:执行构造器方法。
  2. 执行init初始化方法。
  3. 执行service方法。
  4. 执行destory方法。

注意:

  • 构造器方法,init方法只有在web工程启动的时候调用一次。
  • 默认情况下tomcat在接收到对当前servlet的第一次请求的时候就会创建此servlet对象;如果在servlet的配置信息中设置load-on-startup标签中可以设置tomcat开启就创建当前servlet对象。
  • service方法,每访问一次就调用一次。
  • distory方法在工程停止的时候调用一次。

1.5 实际使用

​ 很少直接实现Servlet接口,都是使用继承HttpServlet的方式实现。

  1. 编程一个类去继承HttpServlet。
  2. 根据需求去重写doPost或者doGet方法。
  3. 在web.xml文件中去配置Servlet程序的访问地址。

1.6 使用idea的方式创建Servlet程序

在需要创建Servlet的包,右键点击,直接创建Servlet程序。
2.servlet相关_第4张图片

1.7 Servlet的继承体系

Servlet接口==>实现类GenericServlet==>子类HttpServlet==>自定义的Servlet程序

图解:
2.servlet相关_第5张图片

1.8 ServletConfig类

​ Servlet程序的的配置信息类。

作用:

  • 可以获取Servlet程序的别名Servlet-name的值。

  • 获取初始化参数:init-param。

  • 获取ServletContext对象。


<servlet>

<servlet-name>HelloServletservlet-name>
<servlet-class>com.atguigu.servlet.HelloServletservlet-class>

<init-param>
    <param-name>usernameparam-name>
    <param-value>rootparam-value>
init-param>
<init-param>
    <param-name>urlparam-name>
    <param-value>jdbc:mysql://localhost:3306/testparam-value>
init-param>
servlet>

<servlet-mapping>
	
	<servlet-name>HelloServletservlet-name>
	
	<url-pattern>/helloServleturl-pattern>  
	
servlet-mapping>

后台的代码实现:

@Override
public void init(ServletConfig servletConfig) throws ServletException {
    System.out.println("2.init方法");
    //1.获取ServletName
    String servletName = servletConfig.getServletName();
    System.out.println("ServletName是:"+servletName);
    //2.获取初始化参数
    Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
    while (initParameterNames.hasMoreElements()){
        String paramName=initParameterNames.nextElement();
        System.out.println("初始化参数:"+paramName+"="+servletConfig.getInitParameter(paramName));
    }
    //3.获取ServletContext
    ServletContext servletContext = servletConfig.getServletContext();
    System.out.println("ServletContext是:"+servletContext);
}

运行结果:
ServletName是:HelloServlet
初始化参数:url=jdbc:mysql://localhost:3306/test
初始化参数:username=root
ServletContext是:org.apache.catalina.core.ApplicationContextFacade@3a93af64

注意:

  • Servlet程序和ServletConfig对象是由Tomcat负责创建,我们负责使用的。Servlet程序默认是第一次访问的时候创建的,ServletConfig是每个Servlet程序被创建的,就创建一个ServletConfig对象==>每一个Servlet程序都维护一个自己的ServletConfig对象。

  • 如果我们使用继承HttpServlet的方式实现Servlet且重写了init方法,且需要获取web.xml中配置的初始化参数,一定要在init中调用super.init(config);否则会造成ServletConfig丢失。

//GenericServlet中的init(ServletConfig config)
public void init(ServletConfig config) throws ServletException {
    this.config = config;  //将config保存了起来。
    this.init();
}

1.9 ServletContext类

1 什么是ServletContext?

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

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

  • ServletContext对象是一个域对象(域对象:可以向Map一样存取数据的对象)。

  • ServletContext对象是在web项目部署的时候创建,销毁的时候销毁。
    在这里插入图片描述
    2 ServletContext的常见作用

  • 获取Web.xml中配置的上下文参数context-param。

  • 获取当前工程路径。格式:/工程路径。

  • 获取工程部署后在服务器硬盘上的绝对路径。

  • 向Map一样存取数据==>多个Servlet共享数据。

	<!--context-param是上下文参数,他属于整个Web工程-->
    <context-param>
        <param-name>user</param-name>
        <param-value>context</param-value>
    </context-param>
    <context-param>
        <param-name>password</param-name>
        <param-value>19971001</param-value>
    </context-param>

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //方式1:ServletContext servletContext = getServletConfig().getServletContext();
    ServletContext servletContext = getServletContext();
    //1.获取上下文参数:context-param:注意和init-param没有任何关系
    String user = servletContext.getInitParameter("user");
    System.out.println("user="+user);
    String password = servletContext.getInitParameter("password");
    System.out.println("password="+password);
    //2.获取当前工程路径
    String contextPath = servletContext.getContextPath();
    //当前工程路径为:/07_servlet
    System.out.println("当前工程路径为:"+contextPath);
    //3.获取工程部署在服务器硬盘上的绝对路径。"/被服务器解析为:http://ip:端口号/工程名称/"
    String realPath = servletContext.getRealPath("/");
    //E:\projects\ideacode\atguigu\JavaWeb\out\artifacts\07_servlet_war_exploded\==>"/"被映射为Idea代码的web目录。
    System.out.println(realPath);
    String realPath1 = servletContext.getRealPath("/imgs");
    System.out.println(realPath1);
    //4.存取数据:注意多个Servlet公用一个servletContext对象==>存储的key-value是公用的。
    servletContext.setAttribute("name","张三");
    System.out.println("name="+servletContext.getAttribute("name"));
}

1.10 HttpServletRequest类

1 HttpServletRequest类有什么用

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

2 常见方法

  • getRequestURI( ):获取请求的资源路径

  • getRequestURL( ):获取请求的统一资源定位符(绝对路径)

  • getRemoteHost( ):获取客户端的 ip 地址

  • getHeader( ):获取请求头

  • getParameter( ):获取请求的参数

  • getParameterValues( ):获取请求的参数值(多个值的时候使用)

  • getMethod( ):获取请求的方式 GET 或 POST

  • setAttribute(key, value):设置域数据

  • getAttribute(key):获取域数据

  • getRequestDispatcher( ):获取请求转发对象

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //1.获取uri:资源路径,不包含协议,ip以及端口号
    String requestURI = req.getRequestURI();
    //07_servlet/requestAPI
    System.out.println("URI=="+requestURI);
    //2.获取URL==>统一资源访问定位符:包含协议,ip,端口号以及资源路径
    StringBuffer requestURL = req.getRequestURL();
    //http://localhost:8080/07_servlet/requestAPI
    System.out.println("URL=="+requestURL);
    //3.获取客户端的ip地址。
    String remoteHost = req.getRemoteHost();
    //idea中使用localhost进行访问是127.0.0.1。如果是真实ip就会获取真实ip
    System.out.println("ip=="+remoteHost);
    //4.获取请求的头参数
    String header = req.getHeader("User-Agent");
    System.out.println("User-Agent=="+header);
    //5.获取请求的类型GET或者POST等
    String method = req.getMethod();
    System.out.println(method);
}

3 获取客户端发送过来的参数

1)API

  • request.getParameter(“key”):获取key的value值

  • request.getParameterValues(“key”):获取key对应的多个value值

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //设置请求体的字符集为UTF-8,从而解决post请求的中文乱码问题。注意:改代码必须在获取请求参数之前调用才有效。
    req.setCharacterEncoding("UTF-8");
    //getParameter():单个值使用
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    //getParameterValues():多个值使用
    String[] hobby = req.getParameterValues("hobby");
    System.out.println("username=="+username);
    System.out.println("password=="+password);
    System.out.println("hobby=="+ Arrays.toString(hobby));

}

2)当请求的方式是post且请求的参数含有中文,则会出现中文乱码问题==>设置请求体的字符集为UTF-8,从而解决post请求的中文乱码问题。

  • API:req.setCharacterEncoding(“UTF-8”);

4 请求的转发

1)什么是请求的转发?

​ 请求转发是指,服务器收到请求后,从一个资源跳到另外一个资源的操作,叫做资源的转发,注意客户端是无法感知的。
2.servlet相关_第6张图片
2)代码实现:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("username");
    System.out.println("servlet1查看了参数:username=="+username);
    request.setAttribute("key","servlet1的专属标记");
    //servlet2的路径:必须以/开头,映射为idea的web目录
    RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
    //进行跳转;传入参数,请求和响应
    requestDispatcher.forward(request,response);
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String username = request.getParameter("username");
    System.out.println("servlet2查看了:username=="+username);
    System.out.println("servlet2查看了:servlet1的key=="+request.getAttribute("key"));
    System.out.println("柜台2开始处理自己的业务!!!");

}

代码执行结果:
servlet1查看了参数:username=="张三"
servlet2查看了:username=="张三"
servlet2查看了:servlet1的key==servlet1的专属标记
柜台2开始处理自己的业务!!!

3)请求转发的特点

  • 对于客户端来说是一次请求,服务器端的行为客户端是无法感知。
  • request域中的数据在转发的过程中是共享的。
  • 可以转发到web-inf目录下,但是不可以访问当前web工程以外的资源,想要访问当前工程外的资源可以使用重定向。

4)请求包含

​ 客户端请求servletA,servletA解决一部分,但是还剩下一部分无法解决,剩下的交给ServletB来进行解决。

5)请求转发和请求包含异同

同:

  • 一个请求被两个servlet处理。
  • 由一个servlet去调用另外一个servlet
  • 请求的方式:要不都get,要不都post
  • 可以通过request实现数据共享

不同:

  • 代码不同:请求转发是forward;请求包含是include。
  • 对于响应体设置
    • 请求转发:a不可以设置响应体,但是b可以响应体。
    • 请求包含,a和b都可以设置响应体,
  • 对于响应头设置
    • 请求转发:a可以设置响应头,b也可以设置响应头
    • 请求包含:a可以设置响应头,b不可以。

测试代码实现:

1)demo01

package com.zhiyou.servlet.includeAndForward;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/forward/servletDemo01")
public class ServletDemo01 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name=request.getParameter("name");
        //获取相应的参数
        System.out.println("demo01:name=="+name);
        //设置请求域对象的信息
        request.setAttribute("age", 18);
        //设置响应头信息
        response.setHeader("demo1", "demo01");
        //设置响应体数据
        response.getWriter().write("demo01-----");
        //设置请求转发
        //request.getRequestDispatcher("/forward/servletDemo02").forward(request, response);
        //设置请求包含
        request.getRequestDispatcher("/forward/servletDemo02").include(request, response);

    }


    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

}

2)demo02

package com.zhiyou.servlet.includeAndForward;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/forward/servletDemo02")
public class ServletDemo2 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String name=request.getParameter("name");
        //获取相应的参数
        System.out.println("demo02:name=="+name);
        //获取请求域对象的信息
        int age=(int)request.getAttribute("age");
        System.out.println(age);
        //设置响应头信息
        response.setHeader("demo2", "demo02");
        //设置响应体数据
        response.getWriter().write("demo02-----");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
}

结果展示:
2.servlet相关_第7张图片

5 base标签的作用

​ 可以设置当前页面中所有相对路径工作时,参照哪个路径来进行跳转,通常情况下设置为当前项目路径。

2.servlet相关_第8张图片

6 相对路径和绝对路径

​ 在javaweb中路径分为绝对路径和相对路径

1)相对路径:

​ . 表示当前目录

​ … 表示式上一级目录

​ 资源名 表示当前目录/资源名

2)绝对路径:从协议开始算起

​ http://ip:port/工程路径/资源路径

7 web中/的不同意义

在web中/是一种绝对路径

  • 如果被浏览器解析为:http://localhost:port/

  • 如果被服务器解析为:http://localhost:port/工程路径

例如:

request.getRequestDispacher("/");

/servlet1;

servletContext.getRealPath("/");

特殊:response.sendRediect("/"); //把"/"给浏览器解析为:http://localhost:port/

1.11 HttpServletResponse类

1 HttpServletResponse类的作用。

​ HttpServletResponse和HttpServletRequest类一样,每次请求进来,tomcat都会创建一个该对象,传递给Servlet程序去使用,HttpServletRequest表示请求过来的信息,HttpServletResponse表示所有响应的信息,如果我们需要设置返回客户端的信息,都可以通过HttpServletResponse对象来进行设置。

2 两个输出流的说明

  • 字节流 getOutputStream(); 常用于下载(传递二进制数据)

  • 字符流 getWriter(); 常用于传递字符串(常用)

注意:两个流同时只能使用一个,否则会报错,如下所示。
2.servlet相关_第9张图片

3 要求往客户端回传字符串数据

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //设置服务器字符集为UTF-8:用于解决中文乱码的问题。
    //resp.setCharacterEncoding("utf-8");
    //通过响应头告诉浏览器也是用utf-8
    //resp.setHeader("Content-Type","text/html;charset=UTF-8");
    //他会同时设置服务器和客户端都是用UTF-8字符集,还设置了响应头。
    resp.setContentType("text/html;charset=UTF-8");
    PrintWriter writer = resp.getWriter();
    writer.write("response的content!!!");
}

4 解决中文乱码问题

方式一:

//设置服务器字符集为UTF-8:用于解决中文乱码的问题。
resp.setCharacterEncoding("utf-8");
//通过响应头告诉浏览器也是用utf-8
resp.setHeader("Content-Type","text/html;charset=UTF-8");

方式二:此方法要在获取流对象之前使用才有效。

//他会同时设置服务器和客户端都是用UTF-8字符集,还设置了响应头。
resp.setContentType("text/html;charset=UTF-8");

5 请求重定向

​ 客户端给服务器发请求,然后服务器告诉客户端一个新的地址,让其去新的地址访问。
2.servlet相关_第10张图片
特点:

  • 浏览器的地址会发生变化==>两次请求==>不共享request域中的数据。

  • 不能访问WEB-INF下的资源,但是可以访问工程外的资源。

方式一:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("到response1一游!");
    //设置响应状态码302.表示是重定向
    response.setStatus(302);
    //设置响应头,表明新的地址信息
  response.setHeader("location","http://localhost:8080/07_servlet/response2");
}

方式二:推荐

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    System.out.println("到response1一游!");
    response.sendRedirect("http://localhost:8080/07_servlet/response2");
}

扩展:

1 常见的get和post方式的的请求

①get

  • form 标签 method=get
  • a 标签
  • link 标签引入 css
  • Script 标签引入 js 文件
  • img 标签引入图片
  • iframe 引入 html 页面
  • 在浏览器地址栏中输入地址后敲回车

②post请求

  • form 标签 method=post

2 get和post两者的区别

  • get不安全,参数直接显示到地址栏,相对来说不安全。
  • 请求参数的位置:get请求的请求参数在请求首行中,对请求的数据量有要求,一般为几kb;post的请求参数在请求体中,适用于提交的数据量大的请求。
  • tomcat8 之前:request.setCharacterEncoding只能设置请求体的编码类型,即post请求有效。对于get方式依旧会出现乱码。

3 请求转发和重定向的区别

  • request域对象共享:
    • 请求转发的request对象中的数据可以在多个servlet之间进行共享
    • 从定向不可以。
  • 地址栏的变化:
    • 请求转发的地址栏不会发生变化,是一次请求。
    • 重定向的地址栏会发生变化,是两次请求。
  • 响应头的设置:
    • 请求转发,a,b都可以设置响应头。
    • 重定向只有b可以设置响应头。
  • 请求参数的获取:
    • 请求转发,a,b都可以获取请求参数。
    • 重定向只有a可以获取,b想要获取,只能进行拼串。
  • 访问的方法类型:
    • 请求转发,a的访问方式取决于访问a的请求的类型。
    • 重定向:一定是get的方式,地址栏的方式进行访问。
  • 状态码不同
    • 请求转发:200。
    • 重定向:302。
  • 访问的资源不同
    • 请求转发可以访问web-inf下的资源,但是只可以访问当前项目下的资源。
    • 重定向不可访问web-inf下的资源,但是可以访问当前服务器的其他项目。

4 乱码的处理

1 页面上:

2 服务器端:request.setCharacterEncoding(“utf-8”);

3 mysql:

​ 安装的时候设置的编码集。

​ 创建表的时候:create table 表名( ) charset=“utf8”

4 服务器端给予响应:

​ response.setCharacterEncoding(“utf-8”);

​ response.setHeader(“content-type”,"text/html;charset=“utf-8”);

5 域对象

​ 在指定的范围内实现数据共享的对象。

request:作用域为一个请求,一个请求被多个资源处理,这个资源就是一个资源链。只适用于请求转发和请求包含的两个servlet中实现数据共享。

session:作用域为一个对话,同一个ip,同一个浏览器对服务的发出的连续性请求。

servletContent:上下文对象,作用域是整个项目。

数。

  • 重定向只有a可以获取,b想要获取,只能进行拼串。
  • 访问的方法类型:
    • 请求转发,a的访问方式取决于访问a的请求的类型。
    • 重定向:一定是get的方式,地址栏的方式进行访问。
  • 状态码不同
    • 请求转发:200。
    • 重定向:302。
  • 访问的资源不同
    • 请求转发可以访问web-inf下的资源,但是只可以访问当前项目下的资源。
    • 重定向不可访问web-inf下的资源,但是可以访问当前服务器的其他项目。

4 乱码的处理

1 页面上:

2 服务器端:request.setCharacterEncoding(“utf-8”);

3 mysql:

​ 安装的时候设置的编码集。

​ 创建表的时候:create table 表名( ) charset=“utf8”

4 服务器端给予响应:

​ response.setCharacterEncoding(“utf-8”);

​ response.setHeader(“content-type”,"text/html;charset=“utf-8”);

5 域对象

​ 在指定的范围内实现数据共享的对象。

request:作用域为一个请求,一个请求被多个资源处理,这个资源就是一个资源链。只适用于请求转发和请求包含的两个servlet中实现数据共享。

session:作用域为一个对话,同一个ip,同一个浏览器对服务的发出的连续性请求。

servletContent:上下文对象,作用域是整个项目。

你可能感兴趣的:(javaweb,java,servlet)