六、Servlet

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

我们写的类HelloServlet--->HttpServlet--->GenericServlet--->Servlet

1、Servlet简介

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

  • sun在这些API中提供一个接口叫做:Servlet,如果你想开发一个Servlet程序,只需要完成:

    • 编写一个类,实现Servlet接口

    • 把开发好的Java类部署到Web服务器中

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

2、HelloServlet

  1. 构建一个普通的maven项目,删掉里面的src目录,以后我们的学习就在这个项目中了创建Moudel(模板);这个空的工程技术Maven主工程;

  2. 关于Maven父子工程的理解:

    父项目中会有

    <modules>
        <module>servlet-01</module>
    </modules>

    子项目中会有(如果子项目中没有,就手动添加上)

      <parent>
        <artifactId>javaWeb-02-servlet</artifactId>
        <groupId>com.lyh</groupId>
        <version>1.0-SNAPSHOT</version>
      </parent>
  3. Maven环境优化

    1. 修改web.xml为最新的

    2. 将maven的结构搭建完整

  4. 编写一个Servlet程序

    1. 编写一个普通类

    2. 实现Servlet接口,这里我们直接继承HttpServlet

      public class HelloServlet extends HttpServlet {
          //由于get或者post只有请求实现的不同方式,可以互相调用,业务逻辑都一样
          @Override
          protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              PrintWriter writer = resp.getWriter();
              writer.print("Hekko,Servlet");
          }
      ​
          @Override
          protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              doGet(req, resp);
          }
      }
      ​
  5. 编写Servlet的映射:我们Java程序,但是要通过浏览器访问,而浏览器需要;连接Web服务器,使用我们需要在web服务器中注册我们写的Servlet,还需给他一个浏览器能够访问的路径

    <!--    注册Servlet-->
        <servlet>
            <servlet-name>hello</servlet-name>
            <servlet-class>com.lyh.Servlet.HelloServlet</servlet-class>
        </servlet>
    <!--    Servlet的请求路径-->
        <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello</url-pattern>
        </servlet-mapping>
  6. 配置Tomcat

  7. 测试

3、Servlet原理

4、Mapping问题

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

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  2. 一个Servlet可以指定多个映射路径

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

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
  4. 指定一些后缀或者前缀等等

    可以自定义后缀实现请求映射

    注意:

    *前面不能加项目映射的路径

    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.lyh</url-pattern>
    </servlet-mapping>
  5. 如果找不到路径会走404页面,如果太丑我们可以给他修改

    创建errorServlet

    package com.lyh.Servlet;
    ​
    import javax.servlet.ServletException;
    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 errorServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html");
            resp.setCharacterEncoding("UTF-8");
            PrintWriter writer = resp.getWriter();
            writer.print("<h1>您的网页找不到</h1>");
        }
    ​
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }

    在web.xml文件创建映射

    <!--    解决404丑的页面-->
        <servlet>
            <servlet-name>error</servlet-name>
            <servlet-class>com.lyh.Servlet.errorServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>error</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
  6. 优先级问题

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

5、ServletContext(上下文)

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

1、共享数据

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

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        this.getInitParameter();初始值参数
//        this.getServletConfig();Servlet配置
//        this.getServletContext(); Servlet上下文
        ServletContext context = this.getServletContext();
        String username="李永辉";
        context.setAttribute("username",username);
​
​
​
    }
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        String username = (String) context.getAttribute("username");
        resp.setCharacterEncoding("UTF-8");
        resp.setContentType("text/html");
        resp.getWriter().print("名字"+username);
    }
<servlet>
    <servlet-name>getc</servlet-name>
    <servlet-class>com.lyh.Servlet.GetServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>getc</servlet-name>
    <url-pattern>/getc</url-pattern>
</servlet-mapping>

阐述结果:先运行第一个,下面那个才能访问到

2、获取初始化参数
<context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306</param-value>
    </context-param>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    String url = context.getInitParameter("url");
    resp.getWriter().print(url);
​
}
3、请求转发
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletContext context = this.getServletContext();
    //转发的请求路径,调用forward实现请求转发
    //转发到另一个页面
    context.getRequestDispatcher("/gp").forward(req,resp);
​
}
<servlet>
    <servlet-name>s4</servlet-name>
    <servlet-class>com.lyh.Servlet.ServletDome04</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>s4</servlet-name>
    <url-pattern>/s4</url-pattern>
</servlet-mapping>
4、读取资源文件

Properties

  • 在Java目录下新建一个properties

  • 在resources目录下新建properties

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

思路:需要一个文件流

username=root
password=123456
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //把资源变成一个流
    InputStream resource = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/lyh/Servlet/aaa.properties");
    //把这个流加载几进去
    Properties properties = new Properties();
    properties.load(resource);
    //获取properties的属性
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    //响应到服务台上
    resp.getWriter().print(username+":"+password);
}

6、HttpServletResponse

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

  • 如果要获得客户端请求过来的参数:找HttpServletRequest

  • 如果要给客户端响应一些信息:找HttpServletResponse

1、简单分类

负责向浏览器发送数据的方法

//流
ServletOutputStream getOutputStream() throws IOException;
​
PrintWriter getWriter() throws IOException;

负责向浏览器发送响应头的方法

void setCharacterEncoding(String var1);
​
void setContentLength(int var1);
​
void setContentLengthLong(long var1);
​
void setContentType(String var1);
​
void setBufferSize(int var1);
​
   void sendError(int var1, String var2) throws IOException;
​
    void sendError(int var1) throws IOException;
​
    void sendRedirect(String var1) throws IOException;
​
    void setDateHeader(String var1, long var2);
​
    void addDateHeader(String var1, long var2);
​
    void setHeader(String var1, String var2);
​
    void addHeader(String var1, String var2);
​
    void setIntHeader(String var1, int var2);
​
    void addIntHeader(String var1, int var2);
2、下载文件
  1. 向浏览器输出消息(可以看上面的例子)

  2. 下载文件

    1. 要获得下载文件的路径

    2. 下载的文件名是啥?

    3. 设置想办法让浏览器能够支持下载我们需要的东西

    4. 获取下载文件的输入流

    5. 创建缓冲区

    6. 获取OutputStream对象

    7. 将FileOutputStream流写到buffer缓冲区

    8. 使用OutputStream将缓冲区中的数据输出到客户端

  3. 代码实现:

        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //        1. 要获得下载文件的路径
            String realPath ="D:\\idea\\Project\\javaWeb-02-servlet\\servlet-03\\src\\main\\resources\\19.jpg";
            System.out.println("下载文件路径:"+realPath);
    //        2. 下载的文件名是啥?
            String fileName = realPath.substring(realPath.lastIndexOf("\\") + 1);
    //        3. 设置想办法让浏览器能够支持下载我们需要的东西
            resp.setHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileName,"UTF-8"));
    //        4. 获取下载文件的输入流
            FileInputStream inputStream = new FileInputStream(realPath);
    //        5. 创建缓冲区
            int len=0;
            byte[] buffer = new byte[1024];
    //        6. 获取OutputStream对象
            ServletOutputStream outputStream = resp.getOutputStream();
    //        7. 将FileOutputStream流写到buffer缓冲区
    //        8. 使用OutputStream将缓冲区中的数据输出到客户端
            while ((len=inputStream.read(buffer))>0){
                outputStream.write(buffer,0,len);
            }
            inputStream.close();
            outputStream.close();
        }
3、验证码功能
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //如何让浏览器3秒自动刷新一次
    resp.setHeader("refresh","3");
    //在内存中创建一个照片
    BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
    //得到照片
    Graphics graphics = image.getGraphics();//笔
    //设置照片背景
    graphics.setColor(Color.cyan);
    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/jpeg");
    //网站存在缓冲,不让浏览器缓冲
    resp.setDateHeader("expires",-1);
    resp.setHeader("Cache-Control","no-cache");
    resp.setHeader("Pragma","no-cache");
    //把照片写到浏览器上
    ImageIO.write(image,"jpg",resp.getOutputStream());
​
}
//生成随机数
private  String makeNum(){
    Random random = new Random();
    String num = random.nextInt(9999999) + "";
    StringBuffer buffer = new StringBuffer();
    for (int i = 0; i < 7 - num.length(); i++) {
        buffer.append("0");
    }
    num  = buffer.toString() + num;
    return num;
}

提醒:别忘了去web.xml配置映射

<servlet>
    <servlet-name>img</servlet-name>
    <servlet-class>com.lyh.Servlet.ImgServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>img</servlet-name>
    <url-pattern>/img</url-pattern>
</servlet-mapping>
4、实现重定向 状态3XX开头就是重定向

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

常见场景:

  • 用户登录

    void sendRedirect(String var1) throws IOException;
  • 测试

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       resp.sendRedirect("/img");//重定向
    }
面试题:请聊一聊重定向和转发的区别?

相同点:

  • 页面都会实现跳转

不同点:

  • 请求转发的时候,url不会发生变化 307

  • 重定向时候,url地址栏会发生变化 302

重定向到另一个页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}这个是当前的项目--%>
<form action="${pageContext.request.contextPath}/login" method="get">
    <p>用户名:<input type="text" name="username" ></p>
    <p>密码:<input type="password" name="password"></p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>success</h1>
​
</body>
</html>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("进来请求了");
    //处理请求
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    //重定向
    resp.sendRedirect("/success.jsp");
}

7、HttpServletRequest

HttpServletRequest代表客户端的请求,用户通过Http访问服务器

1、获得前端传递的参数,请求转发
  1. 两个方法

    //获得前端name的值,一个一个获取
    String getParameter(String var1);
    ////获得前端name的值,返回成一个数组
    String[] getParameterValues(String var1);
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //请求响应都设置为中文,不会乱码,到时候我们会学一个过滤器,到时候请求响应乱码都会放在过滤器中
            req.setCharacterEncoding("utf-8");
            resp.setCharacterEncoding("utf-8");
            //抓取前端的name
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            //获得多个name的值
            //String[] hobbys = req.getParameterValues("hobbys");
            //  这里的/ 代表当前web项目
            req.getRequestDispatcher("/success.jsp").forward(req,resp);
        }
    <servlet>
        <servlet-name>LoginServlet</servlet-name>
        <servlet-class>com.lyh.servlet.LoginServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>LoginServlet</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
posted @ 2022-12-04 19:11  菜鸡前来  阅读(16)  评论(0编辑  收藏  举报