Java教程

JAVAWEB - Servlet原理及其使用>从零开始学JAVA系列

本文主要是介绍JAVAWEB - Servlet原理及其使用>从零开始学JAVA系列,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

目录
  • Servlet原理及其使用
    • 什么是Servlet
    • Servlet的使用
      • 编写一个Servlet,使用继承HttpServlet的方式
      • 配置web.xml
      • 很简单的几个JSP文件
      • 小提示,如果继承HttpServlet发现找不到类的时候,引入一个jar包添加到类路径(必须放在WEB-INF目录下)
      • Servlet读取配置(自身Servlet配置、全局配置)
        • 获得Servlet自己的配置信息
        • 获得全局配置信息
      • 解决HTTP请求当中的乱码问题(get、post、response)
        • response响应乱码
        • post请求时接收参数乱码
        • get请求时,接收浏览器的url中的参数时乱码
      • Servlet的注解支持(代替xml配置servlet方式)
    • Servlet的原理
      • Servlet的响应原理
      • Servlet的生命周期
      • Servlet的加载时机
      • Servlet的API关系
        • 为什么继承了HTTPServlet不重写Service访问时会出现405报错?
          • HTTPServlet为什么要这么处理?
          • 为什么service()方法是处理请求的,但是重写doGet、doPost()等方法也有效?
    • Servlet运行的Web项目中的4种路径问题
      • 1、绝对路径(访问任何资源)
      • 2、根路径(访问当前服务器的任何资源)
      • 3、相对路径(访问当前服务器的资源)、不推荐
      • 4、相对路径(基于base标签,访问当前项目,其实实质还是绝对路径或根路径)
        • 使用idea配置模板
      • 不同路径的使用场景
    • 转发与重定向的原理及区别
      • 原理不同
      • 语法实现方式不同
      • 获取request作用域数据问题
      • 跳转页面后,网址的显示不同
      • 书写代码时,使用“ / ”的意义不同
      • 支持书写的路径不同
      • 使用表单时重复提交问题
      • 效率问题
      • 是否经过配置的过滤器
    • 小提示,如何在项目中访问到Servlet

Servlet原理及其使用

什么是Servlet

是JAVA的基于WEB服务器的完成动态网页开发的一种技术

Servlet的使用

编写一个Servlet,使用继承HttpServlet的方式

package com.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
public class MyFirstServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取表单提交的参数,填写的参数是表单对应数据的name属性
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        if(username.equals("dqx") && password.equals("123")) {
            // 转发到/success.jsp
            req.getRequestDispatcher("/success.jsp").forward(req,resp);
        }else {
            // 在request作用域中存入一个 key value
            req.setAttribute("msg", "用户名或密码错误");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }
    }
}

配置web.xml

    <servlet>
        <servlet-name>loginServlet</servlet-name>
        <servlet-class>com.it.servlet.MyFirstServlet</servlet-class>
        <!-- 配置在服务器启动时加载Servlet -->
        <load-on-startup>0</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>loginServlet</servlet-name>
        <!-- 处理的请求 -->
        <url-pattern>/doLogin</url-pattern>
    </servlet-mapping>

很简单的几个JSP文件

  • login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <%
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
    %>
    <base href="<%=basePath%>">
</head>
<body>
<form action="doLogin" method="post">
    <%
        String msg = (String) request.getAttribute("msg");
        System.out.println("---------");
        if(msg != null) {
            out.print(msg);
        }
    %>
    <hr>
    用户名:<input type="text" name="username"> <br>
    密码:<input type="password" name="password"> <br>
    <input type="submit" value="登录">
</form>
</body>
</html>
  • success.jsp
<h1>登录成功</h1>

小提示,如果继承HttpServlet发现找不到类的时候,引入一个jar包添加到类路径(必须放在WEB-INF目录下)

image
——————————————————————————————————
image

Servlet读取配置(自身Servlet配置、全局配置)

为什么需要读取配置?
答:因为有些配置是固定的(例如编码),许多地方都要使用到,而如果硬编码的话,一旦编码改变,则需要更改多处,影响维护。

获得Servlet自己的配置信息

  • 在web.xml中配置参数
    <servlet>
        <servlet-name>myConfigServlet</servlet-name>
        <servlet-class>com.it.servlet.MyConfigServlet</servlet-class>
        <!-- 配置Servlet配置参数 -->
        <init-param>
            <param-name>charset</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </servlet>
  • 在Servlet中获取配置信息(可以在构造函数、init()方法、等等地方都能获取到)
public class MyConfigServlet extends HttpServlet {
    private String charset;
    @Override
    public void init() throws ServletException {
        // 获得Servlet参数,这两种方式是一样的
        charset = this.getInitParameter("charset");
        charset = this.getServletConfig().getInitParameter("charset");
    }

获得全局配置信息

  • 在web.xml中配置全局参数
    <context-param>
        <param-name>globalCharset</param-name>
        <param-value>GBK</param-value>
    </context-param>
  • 在Servlet中获取
public class MyConfigServlet extends HttpServlet {
    private String globalCharset;
    @Override
    public void init() throws ServletException {
        // 获得全局配置参数
        globalCharset = this.getServletContext().getInitParameter("globalCharset");
        System.out.println(globalCharset);
    }

解决HTTP请求当中的乱码问题(get、post、response)

response响应乱码

  • response响应乱码出现的原因?
    答:由于浏览器不知道服务器响应的内容是什么编码的,浏览器默认使用GBK编码,而如果服务器响应的数据是不是GBK编码的时候,浏览器就会乱码
  • 解决方法
    答:在响应中告知浏览器以什么编码来解析数据
// 注意,这里是因为演示,所以硬编码了,实际编码应该从配置中读取
// 这句话就是告知浏览器接收到响应数据时以何种类型处理,以何种编码解析
resp.setContentType("text/html;charset=UTF-8");

post请求时接收参数乱码

  • post请求出现乱码的原因
    答:浏览器进行post请求时(表单提交),浏览器的页面编码与服务器接收处理参数的编码不一致时,就会出现乱码。
  • 解决方法,设置request处理请求参数的编码
request.setCharacterEncoding("UTF-8");

get请求时,接收浏览器的url中的参数时乱码

  • get请求出现乱码的原因
    答:浏览器进行get请求(参数是在URI上)时,浏览器的页面编码(例如浏览器该页面是UTF-8编码)与服务器接收处理URI参数的编码(tomcat默认是IOS-8895-1)不一致时,就会出现乱码。
  • 解决方案有2种
    • 通过修改tomcat服务器中的conf目录中的server.xml文件,添加URIEncoding配置
        <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" URIEncoding="utf-8" />
    
    • 在接受参数后,将数据转换为与页面提交的数据一致的编码
    byte[] bytes = username.getBytes("ISO-8859-1");
    String newUsername = new String(bytes,"UTF-8");
    

Servlet的注解支持(代替xml配置servlet方式)

可以在Servlet类上使用注解的方式代替在web.xml中的配置

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

@WebServlet(loadOnStartup = 0,
        initParams = {@WebInitParam(name = "charset",value = "UTF-8"),@WebInitParam(name = "key2",value = "value2")},
        urlPatterns = "/AnnoServlet")
public class AnnoServlet extends HttpServlet {
}

Servlet的原理

Servlet的响应原理

  • 浏览器发送请求到服务器
  • 服务器通过web.xml中配置的servlet-mapping找到对应的映射
  • 通过匹配到映射找到对应的servlet,通过反射创建其对象
  • 调用该对象中的service方法处理请求
  • 处理请求后使用将响应结果传输给浏览器

Servlet的生命周期

  • 类加载(Servlet加载)
  • 实例化(利用反射创建对象,单例)
  • init初始化
  • service 处理请求
  • destroy 销毁

Servlet的加载时机

  • 在Servlet第一次处理请求时加载(默认)
  • 在服务器启动时就进行加载,在web.xml中对应的servlet标签中添加load-on-startup标签(一般值为0-10),优先级从大到小

Servlet的API关系

  • javax.servlet.Servlet接口
  • javax.servlet.GenericServlet 抽象类,实现了Servlet接口
  • javax.servlet.http.HttpServlet 普通类,继承了GenericServlet抽象类
    所以,想要编写一个Servlet必须要实现或者间接实现Servlet接口,一般使用最多的就是继承HttpServlet
  • 常用方法
// Servlet接口中的方法
void service(ServletRequest var1, ServletResponse var2);//核心方法,用于处理浏览器发送的请求
ServletConfig getServletConfig(); //用于获取Servlet的配置信息

为什么继承了HTTPServlet不重写Service访问时会出现405报错?

答:因为继承了HTTPServlet方法没有重写service()方法或doGet()、doPost()方法
image

image

HTTPServlet为什么要这么处理?

答:因为本身我们开发者编写一个Servlet类就是为了处理请求,而既没有service()方法处理请求,也没有doGet()、doPost(),那这个Servlet存在的意义就缺失了。所以HttpServlet处理时就直接报错,是为了告知调用者重写service()或者doGet()、doPost()等方法

为什么service()方法是处理请求的,但是重写doGet、doPost()等方法也有效?
  • HttpServlet中通过获得请求的方式(get、post)后,还是会调用doGet、doPost等方法
  • 如果继承了HttpServlet的类重写了doGet方法,那么最后HttpServlet中的service方法在执行时判断了请求的方式是get请求后,会执行子类重写的doGet方法(多态)。

Servlet运行的Web项目中的4种路径问题

1、绝对路径(访问任何资源)

// 格式: 协议://IP地址:端口号/资源路径
<a href="http://127.0.0.1:8080/myProject1/path1/update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
<a href="http://127.0.0.1:8080/myProject1/path1/subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
<a href="http://127.0.0.1:8080/myProject1/path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
<a href="http://127.0.0.1:8080/myProject1/index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
<a href="http://127.0.0.1:8080/myProject1/servlet/DoLogin2">访问servlet的路径</a> <br/>
<a href="http://127.0.0.1:8080/myProject1/index.jsp">同一个服务器中不同项目中的文件servlet01/index.jsp</a> <br/>
<a href="http://192.168.121.33:8080/demo/a.jsp">同一个局域网中不同服务器中的项目</a> <br/>
<a href="http://www.baidu.com">外网服务器的项目</a> <br/>

2、根路径(访问当前服务器的任何资源)

提示:只能访问当前服务器的任何资源

<a href="/webdemo01/path1/update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
<a href="/webdemo01/path1/subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
<a href="/webdemo01/path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
<a href="/webdemo01/index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
<a href="/webdemo01/servlet/DoLogin2">访问servlet的路径</a> <br/>
<a href="/webdemo01/index.jsp">同一个服务器中不同项目中的文件servlet01/index.jsp</a> <br/>
<%--不行--%>
<a href="/demo/a.jsp">同一个局域网中不同服务器中的项目</a> <br/>

3、相对路径(访问当前服务器的资源)、不推荐

<a href="update.jsp">同一个项目下同一个文件夹中的文件update.jsp</a> <br/>
<a href="subpath/delete.jsp">同一个项目下同子文件夹中的文件delete.jsp</a> <br/>
<a href="../path2/add.jsp">同一个项目下同级文件夹中的文件add.jsp</a> <br/>
<a href="../index.jsp">同一个项目下父级文件夹中的文件index.jsp</a> <br/>
<a href="../servlet/DoLogin2">访问servlet的路径</a> <br/>
<a href="../../myProject2/index.jsp">同一个服务器中不同项目中的文件

4、相对路径(基于base标签,访问当前项目,其实实质还是绝对路径或根路径)

<head>
    <%
        // 这是绝对路径的base标签
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";

        // 根路径的base标签
        String genBasePath = request.getContextPath() + "/";
    %>
    <base href="<%=genBasePath%>">
</head>
<body>
    <%-- 注意,这里不要在写一个/了,不然就变成根路径与base标签无关了了 --%>
    <a href="index.jsp">访问index.jsp</a>
</body>

使用idea配置模板

image

不同路径的使用场景

  • 路径适用于jsp页面中的 a、form、src、link等等
  • 访问其他服务器时:绝对路径
  • 访问自己服务器其他项目时: 根路径
  • 访问当前项目:base路径

转发与重定向的原理及区别

原理不同

  • 转发,指的是在服务器跳转
    服务器在内部接收到第一个请求时,转发到其他servlet或页面处理,然后返回数据给用户。
    这个过程用户是不可见的,所以转发时,浏览器只会向服务器发出一个请求

  • 重定向,客户端跳转
    服务器在运行到重定向的语句时,将重定向请求发回给浏览器,其状态码为302(并携带者需要重定向的资源路径)
    浏览器在接收到这个302的重定向响应后,用其中的资源路径地址再次向服务器发送一个请求
    所以这个过程中涉及到了2个请求。所以重定向是用户可见的。

语法实现方式不同

// 转发(这里使用的是相对路径)
req.getRequestDispatcher("index.jsp").forward(req, resp);

// 重定向(这里使用的是相对路径)
resp.sendRedirect("index.jsp");

获取request作用域数据问题

转发能够获取request作用域中的数据,因为其转发的原理就是至始至终都只有一个请求,而request作用域的范围就是一个请求当中,所以能够获取

重定向不能获取request中的数据,因为重定向时,涉及到了2个请求,所以第二个请求已经不在第一个请求的作用范围内了,所以无法获取。

跳转页面后,网址的显示不同

转发跳转后,由于是服务器内部跳转,浏览器无法察觉,所以还是显示的浏览器访问的资源路径。
重定向跳转后,由于是客户端跳转,跳转对浏览器是可见的,所以显示的路径是重定向的路径。

书写代码时,使用“ / ”的意义不同

转发时候的字符串时候由于路径最前面会加上/项目名,所以写 / 代表着当前项目,这也意味着。转发只能转发到当前的项目资源。

支持书写的路径不同

绝对路径
转发:不支持
重定向:支持
相对路径(不推荐)
转发:支持
重定向:支持
根路径
转发:支持(当前项目)
重定向:支持(代表当前服务器,与在jsp中使用根路径是一样的)

使用表单时重复提交问题

效率问题

是否经过配置的过滤器

小提示,如何在项目中访问到Servlet

其实每编写一个Servlet并使用web.xml配置好、或者使用注解的方式配置了一个Servlet时。
就相当于在Web根路径下放入了这个Servlet。

image
image

这篇关于JAVAWEB - Servlet原理及其使用>从零开始学JAVA系列的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!