Servlet

简介

sun公司开发动态web的一门技术,sun在这些api中提供一个接口叫做Servlet,如果你想开发一个Servlet程序,只需要完成2步:

(1)编写一个类,实现Servlet接口。
(2)把开发好的java类部署到web服务器中。

把实现了Servlet接口的java程序叫Servlet。

 

编写一个Servlet

(1)编写一个普通的类

(2)实现Servlet接口,这里我们直接继承 HttpServlet(HttpServlet如果之前没有用到此包,需要从maven仓库下载,本人从maven仓库下载完,安装好依赖,访问时报错了,大体意思为:我们编写的类不是Servlet,在下边有解决方案

(3)重写Servlet的 doGet 和 doPost 方法

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       PrintWriter write = resp.getWriter(); // 创建响应流
        write.print("哈哈;");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

(4)编写Servlet的映射

为什么需要映射:我们写是java程序,但是要通过浏览器访问,而浏览器需要连接web服务器,所以我们需要在web服务器中注册我们写的Servlet,还需要给它一个浏览器访问的路径。

在webapp -> WEB-INF -> web.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0"
         metadata-complete="true">
<!--
客户端请求时,会请求 http://localhost:8080/servlet_03_01_war/hello
根据/hello 会找到name为hello的类,然后根据com.lxc.HelloServlet找到我们编写的
对应的java程序类。
-->
<!--注册Servlet-->
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.lxc.HelloServlet</servlet-class>
  </servlet>
<!--Servlet的请求路径-->
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>
</web-app>

(5)注意一个问题,输入路径访问时,有可能报类似如下的错误:

首先,先去检查下是类名、和配置的Servlet映射是否正确,如果都对的话,那百分之99的问题出在jar包依赖的问题上,tomcat10之后不是 javax.servlet 了,而是 jakarta.servlet,所以Web的依赖应该换成下面的这两个,换了之后就对了。
pom.xml中把原来的依赖更换成如下代码,此时就能仿问了:

<!--jsp的依赖-->
    <dependency>
      <groupId>jakarta.servlet.jsp</groupId>
      <artifactId>jakarta.servlet.jsp-api</artifactId>
      <version>3.0.0</version>
      <scope>provided</scope>
    </dependency>

<!--jar包的依赖-->
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>5.0.0</version>
      <scope>provided</scope>
    </dependency>

Mapping 

(1)一个Servlet可以指定一个映射路径

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

(2)一个Servlet可以指定多个映射路径
多个路径,都会被映射到名字为hello对应的类中

<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>/hello</url-pattern>
</servlet-mapping>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello1</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello2</url-pattern>
  </servlet-mapping>
</web-app>

(3)一个Servlet可以指定通用映射路径
下边代表 /hello/ 后边不管写什么东西, 都会被映射到名字为hello对应的类中

<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>/hello/*</url-pattern>
</servlet-mapping>


(4)指定一些后缀
下边写法,只要后缀时.xxx的被映射到名字为hello对应的类中

<servlet-mapping>
  <servlet-name>hello</servlet-name>
  <url-pattern>*.xxx</url-pattern>
</servlet-mapping>

404页面

(1)默认的404页面,是由Servlet提供的,如果不想使用它的,我们可以定义404页面

// 创建Error类
public class Error extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html");
        PrintWriter write = resp.getWriter();
        write.print("<h1>404</h1>");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

Servlet映射
error我们使用的 /*  通配符,他的优先级是最低的,固有的路径的优先级最大,所以当我们当问/hello时,走的是名字为hello对应的类中,如果没在这里映射,那么他会走我们编写的error页面!

  <!--注册Servlet-->
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.lxc.HelloServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>hello</servlet-name>
    <url-pattern>/hello/*</url-pattern>
  </servlet-mapping>
  <!--Error类的映射-->
  <servlet>
    <servlet-name>error</servlet-name>
    <servlet-class>com.lxc.Error</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>error</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>


 

 

Servlet常用API

(1)getServletContext - 实例方法

web容器在启动的时候,都会为每个web容器创建一个ServletContext上下文对象且是唯一的,它代表了当前的web应用,而这个上下文对象我们可以使用它来做数据共享。
getServletContext 返回的是一个上下文对象,Servlet之间通信可以使用该方法,来传递数据。

web.xml中的配置就不展示了

// User.java
public class User extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setCharacterEncoding("utf-8"); // 设置编码
        resp.setContentType("text/plain");

        ServletContext ctx = this.getServletContext(); // 获取上下文
        String name = "吕星辰";
        ctx.setAttribute("name", name); // 保存数据
        resp.getWriter().print("数据保存成功!");
    }
}
// getUserInfo.java
public class GetUserInfo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain");
        resp.setCharacterEncoding("utf-8");

        ServletContext ctx = this.getServletContext();
        // getAttribute返回的结果Object对象,所以需要强转为String
        String res = (String) ctx.getAttribute("name");
        resp.getWriter().print("返回的结果为:"+res);
    }
}

 输出结果:

 

(2)ctx.getInitParameter 获取初始化参数 - 上下文对象中的方法

<!--web.xml-->
<!--···-->
<context-param>
  <param-name>name</param-name>
  <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
</context-param>
<!--···-->
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext ctx = this.getServletContext(); // 获取上下文
    // 获取web.xml中初始化的参数  jdbc:mysql://localhost:3306/mybatis
    String name = ctx.getInitParameter("name");
}

 

 (3)ctx.getRequestDispatcher(String url)  请求转发 - 上下文对象中的方法
注意,此方法转发之后路径不会改变,与重定向的区别是:重定向之后页面URL会变化。

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext ctx = this.getServletContext(); // 获取上下文
    RequestDispatcher dir = ctx.getRequestDispatcher("/redirect"); // 转发到 "/redirect"对应的页面
    dir.forward(req, resp);
}

 

(4)ctx.getResourceAsStream( ) 读取资源文件

在resources中创建了 dn.properties 的资源文件,我们来定义用户名和密码: 

在ReadFile.java中读取它:

public class ReadFile extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext ctx = this.getServletContext();
        // 获取资源的流
        InputStream streams = ctx.getResourceAsStream("/WEB-INF/classes/db.properties");
        // 关于Properties 会有专门的一篇文章记录
        Properties prop = new Properties();
        prop.load(streams); // 加载流
        String username = prop.getProperty("username"); // 读取属性
        String password = prop.getProperty("password");
        resp.getWriter().print("username:"+username+",password:"+password);
    }
}

 上边getResourceAsStream() 中的参数是资源的路径,在项目打包编译之后,会生成target文件,我们只需要查看资源打包编译之后,在哪里即可,这样项目部署在服务器上的时候,就不需要更改资源路径了。

注意一个问题:
如果资源文件没有放到 resources文件下,放到了别的地方,此时,打包编译之后,资源文件会被忽略,不会被打包进去,解决这个问题,我在Maven下载安装配置一文中已经记录。

 

(5)resp.sendRedirect()重定向

public class Response extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/redirect"); // 重定向到 redirect路径
    }
}

原理

public class Response extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // resp.setHeader("localtion", "/redirect"); // 参数二为重定向的路径
        // resp.setStatus(302);
        resp.sendRedirect("/redirect"); // 重定向到 redirect路径
    }
}

重定向与转发的区别

不同点:转发url不会发生变化;重定向url会发生变化。
相同点:页面跳转

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值