当前位置:网站首页>Servlet详解

Servlet详解

2022-08-09 07:56:00 Zero摄氏度

Servlet详解

1、Servlet简介

  • sun公司开发动态web的一门技术

  • Sun公司在这些api中提供了一个接口:Servlet,如果想开发一个Servlet程序,需要完成两个步骤:

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

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

2、HelloServlet

Servlet接口Sun公司有两个默认的实现类,HttpServlet,GenericServlet

  • 建立一个普通的Maven项目,删除其中的src文件,在这个项目里建立module,这个空的工程就是Maven主工程;
  • 创建子项目
  • 关于Maven父子工程的理解:

父项目中会出现

 <modules>
        <module>servlet02</module>
 </modules>

子项目中:

<parent>
        <artifactId>javaweb-01-servlet</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

父项目中的jar包子项目可以直接使用

Maven环境优化:

  • 换最新的web.xml------在下载的tomcat中,网站例子里有一个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">
</web-app>

  • 搭建完整maveb结构:在main创建两个目录,一个test(标记为测试),一个resource(资源类)

  • 编写一个servlet程序

    • 1.编写一个普通类,实现Servlet接口,这里我们直接继承HttpServlet
    package com.qian.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    public class HelloServlet extends HttpServlet {
          
        //由于get或者post只是请求实现的不同的方式,可以相互调用,业务逻辑一样
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
            //ServletOutputStream outputStream = resp.getOutputStream();
            PrintWriter writer = resp.getWriter();//响应流
            writer.print("hello,Servlet");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
          
            super.doPost(req, resp);
        }
    }
    
    

分析源码:

  • servlet接口---->GenericServlet------>HttpServlet----->我们的java类:
public interface Servlet {
    
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}


GenericServlet implements Servlet{
    }
HttpServlet extends GenericServlet{
    }

所以我们自己的类只需要继承HttpServlet即可

  • 2.编写Servlet的映射,我们写的是java程序,但是要通过浏览器访问,浏览器需要连接web服务器,所以需要在web服务中注册我们写的servlet,还需要给他一个浏览器能访问的路径
<!-- 注册servlet-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.qian.servlet.HelloServlet</servlet-class>
    </servlet>
<!-- servlet的请求路径-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

  • 3.配置Tomcat

配置项目发布路径就可以

  • 4.启动测试

3、Servlet原理

Servlet是由Web服务器调用,web服务器在收到浏览器请求后,从Servlet中的service方法拿到请求并且传给相应。

  • servlet实现过程:

(1)客户端发送请求至服务器端;

(2)服务器将请求信息发送至 Servlet;

(3)Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;

(4)服务器将响应返回给客户端。

  • servlet可以完成:

(1)动态生成HTML文档。

(2)将请求转发给Servlet组件。

(3)读取客户端的Cookie,以及向客户端写入Cookie。

(4)访问服务器的资源,如数据库、 XML、文件对像等。

  • public interface Servlet {
          
        void init(ServletConfig var1) throws ServletException;
    
        ServletConfig getServletConfig();
    
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
        String getServletInfo();
    
        void destroy();
    }
    
    

4、 mapping问题

  • 一个servlet可以指定一个映射路径
 <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  • 一个servlet指定多个映射路径
 <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>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello3</url-pattern>
    </servlet-mapping>
  • 一个Servlet可以指定通用映射路径
 <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello/*</url-pattern>
    </servlet-mapping>

  • 指定一些后缀或者前缀等待
<!-- servlet的请求路径 可以自定义后缀实现请求映射,注意点,*前面不能加项目映射路径 -->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

  • 优先级问题

指定了固有的映射路径优先级最高,如果找不到就会走默认的处理请求

  <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.qian.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>


    <servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.qian.servlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

5、ServletContext

web容器在启动的时候,它会为每个web程序都创建一个对应的ServletContext对象,它代表了当前的web应用;

  • 1)共享数据

我在这个Servlet中保存的数据,可以在另外一个Servlet中拿到

//放置数据的类 
@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //this.getInitParameter() 初始化参数
        // this.getServletContext() Servlet配置
       //this.getServletConfig Servlet上下文
        ServletContext servletContext = this.getServletContext();
        String username = "王也"; //数据
        servletContext.setAttribute("username",username);//将一个数据保存在了ServletContext中,名字为username,值为“王也”

        }

//读取数据的类
 @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext servletContext = this.getServletContext();
        String username = (String) servletContext.getAttribute("username");

        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字"+username);
    }
  <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.qian.servlet.HelloServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>getc</servlet-name>
        <servlet-class>com.qian.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>getc</servlet-name>
        <url-pattern>/getc</url-pattern>
    </servlet-mapping>

测试访问:先访问hello网页,再访问getc,就可以拿到共享数据

  • 2)获取初始化参数

在web.xml中可以配置初始化参数

<context-param>
        <param-name>url</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 context = this.getServletContext();
        //获取初始化参数
        String url = context.getInitParameter("url");
        resp.getWriter().print(url);

    }

在servlet中注册

 <servlet>
        <servlet-name>gp</servlet-name>
        <servlet-class>com.qian.servlet.ServletDemo03</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>gp</servlet-name>
        <url-pattern>/gp</url-pattern>
    </servlet-mapping>

测试结果。

  • 3)请求转发

写请求转发类

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        ServletContext context = this.getServletContext();
        System.out.println("进入了ServletDemo04");
       context.getRequestDispatcher("/gp").forward(req,resp);  //转发的请求路径 调用forward实现请求转发


    }

注册

<servlet>
        <servlet-name>sd</servlet-name>
        <servlet-class>com.qian.servlet.ServletDemo04</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd</servlet-name>
        <url-pattern>/sd</url-pattern>
    </servlet-mapping>
  • **4)读取资源文件 **

Properties:

在java目录下新建properties

在resources目录下新建properties

都被打包到了同一个路径下:classes,我们俗称这个路径为classpath

读取资源的类

@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
        Properties prop = new Properties();
        prop.load(is);
        String username = prop.getProperty("username");
        String password = prop.getProperty("password");
        resp.getWriter().print(username+":"+password);

    }

注册

 <servlet>
        <servlet-name>sd5</servlet-name>
        <servlet-class>com.qian.servlet.ServletDemo05</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>sd5</servlet-name>
        <url-pattern>/sd5</url-pattern>
    </servlet-mapping>

测试结果即可

6、HttpServletResponse

1)web服务器接收到客户端的http请求,针对这个请求,分别创建一个代表请求的HttpServletRequest对象,代表相应的一个HttpServletResponse;

  • 如果要获取客户端请求过来的参数:找HttpServletRequset
  • 如果要给客户端相应一些信息:找HttpServletResponse

2)常见应用

  • 向浏览器输出消息
  • 下载文件
    • 获取下载文件的路径
    • 下载的文件名是什么
    • 设置想办法让浏览器支持下载我们需要的东西
    • 获取下载文件的输入流
    • 获取OutPutStram对象
    • 将fileOutPutStram流写入到buffer缓冲区
    • 使用OutPutStram将缓冲区的数据输出到客户端
//下载文件
public class FileServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //1.获取下载文件的路径
        String realPath = "D:\\IDEA\\javaweb-01-servlet\\response\\target\\response\\WEB-INF\\classes\\小姐姐.jpg";
        System.out.println("下载文件的路径:"+realPath);
        //2.下载的文件名
        String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
        //3.设置让浏览器能够支持下载我们需要的东西,中文文件名: URLEncoder.encode(fileName,"UTF-8")
        //web下载文件应该设置的头文件 resp.setHeader("Content-disposition","attachment;filename"+ URLEncoder.encode(filename));
        resp.setHeader("Content-disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
        //4.获取下载文件的输入流
        FileInputStream in = new FileInputStream(realPath);
        //5.创建缓冲区
        int len = 0;
        byte[] buffer = new byte[1024];
        //6.获取OutPutStream对象
        ServletOutputStream outputStream = resp.getOutputStream();
        //7.将 FileInputStream流写入到buffer缓冲区 ,使用OutPutStream将缓冲区中的数据输出到客户端
        while((len = in.read(buffer))>0){
    
            outputStream.write(buffer,0,len);
        }
        in.close();
        outputStream.close();



    }
  • 验证码功能
    • 后端实现:需要用到java的图片类,生产了一个图片
public class ImageServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        //如何让浏览器五秒自动刷新一次
        resp.setHeader("refresh","3");

        //在内存中创建一个图片
        BufferedImage bufferedImage = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics();//一支笔
        //设置图片的背景颜色
        graphics.setColor(Color.BLUE);
        graphics.fillRect(0,0,80,20);
        //给图片写数据
        graphics.setColor(Color.BLACK);
        graphics.setFont(new Font(null,Font.BOLD,20));
        graphics.drawString(makeNum(),0,20);

        //告诉浏览器,这个请求用图片的方式打开
        resp.setContentType("image/jpg");
        //网站存在缓存,不让浏览器缓存
        resp.setDateHeader("expires",-1);
        resp.setHeader("Cache-Control","no-cache");
        resp.setHeader("Pragma","no-cache");

        //把图片写给浏览器
        ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());

    }
    //生成随机数
    private String makeNum(){
    
        Random random = new Random();
        String num = random.nextInt(99999999) + "";
        StringBuffer sb = new StringBuffer();
        for (int i = 0;i<7-num.length();i++){
    
            sb.append("0");
        }
        String s = sb.toString()+num;
        return num;
    }

  • 实现重定向 (重点)

1)B一个web资源收到客户端A请求后,B他会通知A客户端去访问另外一个web资源C,这个过程叫重定向

2)常见场景:

​ 用户登录:

 resp.sendRedirect("/r2/image");  //会跳转到指定页面

3)重定向和转发的区别?

相同点:页面都会实现跳转

不同点:

  • 请求转发时,url不会产生变化
  • 重定向转发时,url会产生变化

4)request中重定向

public class RequestTest extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
        System.out.println("进入这个请求了");
        //处理请求
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        System.out.println(username+":"+password);
        //重定向时候一定要注意路径问题,否则404
        resp.sendRedirect("/r2/xqh.jsp");

    }
  
  web.xml
  <servlet-mapping>
        <servlet-name>Requset</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
    
    //index.jsp
    <form action="${pageContext.request.contextPath}/login"method="get">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit">
</form>

7、HttpServletRequest

代表客户端的请求,用户通过Http协议访问服务器,Http请求中的所有信息会被封装到HttpServletRequest,通过这个HttpServletRequest的方法,获得客户端的所有信息。

1)获取前端传递的参数 (以登录为例子)

  • 获取参数java
public class LoginServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
       req.setCharacterEncoding("utf-8");
       resp.setCharacterEncoding("utf-8");
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String[] hobbies = req.getParameterValues("hobby");
        System.out.println("===============================");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies));
        System.out.println("===============================");
        //通过请求转发
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
    }
  • 主页代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<h1>登录</h1>
<div style="text-align: center">
    <form action="${pageContext.request.contextPath}/login"method="post">
        用户名:<input type="text"name="username"><br>
        密码:<input type="password"name="password"><br>
        爱好:
        <input type="checkbox"name="hobby"value="唱歌">唱歌
        <input type="checkbox"name="hobby"value="代码">代码
        <input type="checkbox"name="hobby"value="画画">画画
        <input type="checkbox"name="hobby"value="游戏">游戏
        <br>
        <input type="submit">
    </form>

</div>
</body>
</html>
  • 登录成功跳转页
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Success</title>

</head>
<body>
<h1>Success</h1>
</body>
</html>
  • 注册页
 <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.qian.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

主页---->登录提交----->提交到/login----->请求转发到success.jsp(登录成功页面)

原网站

版权声明
本文为[Zero摄氏度]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_56116754/article/details/123957334