加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

Servlet

发布时间:2020-12-15 06:50:23 所属栏目:Java 来源:网络整理
导读:Servlet 目录 Servlet 1. Servlet简介 2. HelloServlet 3. Servlet原理 4. Mapping问题 5. ServletContext 1. 共享数据 2. 获取初始化参数 3. 请求转发 4. 读取资源文件 6. HttpServletResponse 1. 简单分类 2. 常见应用 7. HttpServletRequset 1. Servlet简

Servlet

目录
  • Servlet
    • 1. Servlet简介
    • 2. HelloServlet
    • 3. Servlet原理
    • 4. Mapping问题
    • 5. ServletContext
      • 1. 共享数据
      • 2. 获取初始化参数
      • 3. 请求转发
      • 4. 读取资源文件
    • 6. HttpServletResponse
      • 1. 简单分类
      • 2. 常见应用
    • 7. HttpServletRequset

1. Servlet简介

  • sun公司开发动态web的一门技术
  • sun公司在这些API中提供一个接口叫做:Servlet。如果你想开发一个Servlet程序,只需要完成两个小步骤
    • 编写一个类,实现servlet接口
    • 把开发好的java类部署到web服务器中

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

2. HelloServlet

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

  1. 构建一个普通的Maven项目,删掉里面的src目录,以后我们的学习就在这里面建立module;这个空的工程就是Maven的主工程;以webapp为模板建立一个子工程

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

    父项目中会有

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

    子项目中会有

        <parent>
            <artifactId>HelloServlet</artifactId>
            <groupId>org.example</groupId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    

    父项目中的jar包子项目中可以直接使用(类似java中的继承)

  3. Maven环境优化

    1. 修改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_4_0.xsd"
      version="4.0"
      metadata-complete="true">
      </web-app>
      
    2. 将maven的结构搭建完整

  4. 编写一个servlet程序

    1. 编写一个普通类

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

      https://www.52php.cn/res/2020/11-24/11/bafd45d04d22fb988ea1443c59994c68.png

      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,Serlvet");
          }
      
          @Override
          protected void doPost(HttpServletRequest req,IOException {
              doGet(req,resp);
          }
      }
      
  5. 编写servlet的映射

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

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

    注意配置项目发布的路径就可以了

  7. 启动测试

注意!写url时不要忘了加/

<!--Servlet的请求路径-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>

3. Servlet原理

servlet是由web服务器调用,web服务器在收到浏览器请求之后会:

https://www.52php.cn/res/2020/11-24/11/8700564f4527f8e60d40f5beb7e6db54.png

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>/hello1</url-pattern>
        </servlet-mapping>
    
  3. 一个Servlet可以指定通用映射路径(通配符)

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

    注意,下面的是默认请求路径,尽量避免这样写!

    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    
  4. 可以自定义后缀实现请求映射

    注意,.*前面不能加项目映射的路径

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

    以下均为非法写法

    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/*.wang</url-pattern>
        </servlet-mapping>
    
    	<servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>/hello/*.wang</url-pattern>
        </servlet-mapping>
    
  5. 优先级问题

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

    例如处理404请求

    <!--404-->
        <servlet>
            <servlet-name>error</servlet-name>
            <servlet-class>com.wang.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中拿到

https://www.52php.cn/res/2020/11-24/11/fcb21f73ff654f12032bdf80e38ff6cb.png

放入——>取出——>配置mapping

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,IOException {

        //this.getInitParameter();      初始化参数
        //this.getServletConfig();      Servlet配置
        //this.getServletContext();     Servlet上下文

        ServletContext context = this.getServletContext();

        String username = "王诗凯";    //数据
        context.setAttribute("username",username); //将一个数据保存在ServletContext中,名字为username,值username

        System.out.println("Hello");
    }

}
public class GetServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req,IOException {
        ServletContext context = this.getServletContext();   //拿到的是同一个ServletContext,因为全局唯一

        String username = (String)context.getAttribute("username");

        //resp.setHeader();
        resp.setContentType("text/html");
        resp.setCharacterEncoding("utf-8");
        resp.getWriter().print("名字 " + username);
    }

    @Override
    protected void doPost(HttpServletRequest req,IOException {
        super.doGet(req,resp);
    }
}
  <servlet>
    <servlet-name>hello</servlet-name>
    <servlet-class>com.wang.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.wang.servlet.GetServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>getc</servlet-name>
    <url-pattern>/getc</url-pattern>
  </servlet-mapping>

测试访问结果

2. 获取初始化参数

  <!--配置一些web应用初始化参数-->
  <context-param>
    <param-name>url</param-name>
    <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
  </context-param>
@Override
    protected void doGet(HttpServletRequest req,IOException {
        ServletContext context = this.getServletContext();   //拿到的是同一个ServletContext,因为全局唯一

        String url = context.getInitParameter("url");
        resp.getWriter().print(url);
    }

3. 请求转发

@Override
    protected void doGet(HttpServletRequest req,IOException {
        ServletContext context = this.getServletContext();   //拿到的是同一个ServletContext,因为全局唯一
        System.out.println("进入了ServletDemo04");
        /*
        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");  //转发请求路径
        requestDispatcher.forward(req,resp);   //调用forward实现请求转发
         */

        context.getRequestDispatcher("/gp").forward(req,resp);
    }

https://www.52php.cn/res/2020/11-24/11/bf5b922658ace152dc2827ba2f261243.png

4. 读取资源文件

Properties

  • 在Java目录下新建properties
  • 在resource目录下新建properties

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

思路:需要一个文件流

@Override
    protected void doGet(HttpServletRequest req,IOException {
        InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");

        Properties prop = new Properties();
        prop.load(is);
        String user = prop.getProperty("username");
        String pwd = prop.getProperty("password");

        resp.getWriter().print(user + ":" + pwd);
    }

访问测试即可

6. HttpServletResponse

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

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

1. 简单分类

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

servletOutputStream getOutputStream() throws IOException;
PrintWriter getWriter() 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);

    void setCharacterEncoding(String var1);

    void setContentLength(int var1);

    void setContentLengthLong(long var1);

    void setContentType(String var1);

响应的状态码

    int SC_CONTINUE = 100;
    int SC_SWITCHING_PROTOCOLS = 101;
    int SC_OK = 200;
    int SC_CREATED = 201;
    int SC_ACCEPTED = 202;
    int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    int SC_NO_CONTENT = 204;
    int SC_RESET_CONTENT = 205;
    int SC_PARTIAL_CONTENT = 206;
    int SC_MULTIPLE_CHOICES = 300;
    int SC_MOVED_PERMANENTLY = 301;
    int SC_MOVED_TEMPORARILY = 302;
    int SC_FOUND = 302;
    int SC_SEE_OTHER = 303;
    int SC_NOT_MODIFIED = 304;
    int SC_USE_PROXY = 305;
    int SC_TEMPORARY_REDIRECT = 307;
    int SC_BAD_REQUEST = 400;
    int SC_UNAUTHORIZED = 401;
    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
    int SC_NOT_ACCEPTABLE = 406;
    int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    int SC_REQUEST_TIMEOUT = 408;
    int SC_CONFLICT = 409;
    int SC_GONE = 410;
    int SC_LENGTH_REQUIRED = 411;
    int SC_PRECONDITION_FAILED = 412;
    int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    int SC_REQUEST_URI_TOO_LONG = 414;
    int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    int SC_EXPECTATION_FAILED = 417;
    int SC_INTERNAL_SERVER_ERROR = 500;
    int SC_NOT_IMPLEMENTED = 501;
    int SC_BAD_GATEWAY = 502;
    int SC_SERVICE_UNAVAILABLE = 503;
    int SC_GATEWAY_TIMEOUT = 504;
    int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

2. 常见应用

  1. 向浏览器输出信息
  2. 下载文件
    1. 要获取下载文件的路径
    2. 下载的文件名是啥?
    3. 设置想办法让浏览器能够支持下载我们需要的东西
    4. 获取下载文件的输出流
    5. 创建缓冲流
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到Buffer缓冲区
    8. 使用OutputStream将缓冲区的数据输出到客户端
@Override
    protected void doGet(HttpServletRequest req,IOException {
        //1. 要获取下载文件的路径
        //D:JavaWebHelloServletresponsetargetclassesTIM截图20200728172813.png
        //String realPath = this.getServletContext().getRealPath("/TIM截图20200728172813.png");
        String realPath = "D:JavaWebHelloServletresponsetargetclassesTIM截图20200728172813.png";
        System.out.println("下载文件的路径:" + realPath);
        //2. 下载的文件名是啥?
        String fileName = realPath.substring(realPath.lastIndexOf("") + 1);
        //3. 设置想办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名用URLEncoder.encode编码,否则可能乱码
        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 out = resp.getOutputStream();
        //7. 将FileOutputStream流写入到Buffer缓冲区
        //8. 使用OutputStream将缓冲区的数据输出到客户端
        while ((len = in.read(buffer)) > 0){
            out.write(buffer,len);
        }

        in.close();
        out.close();
    }
  1. 验证码功能

    验证码怎么来的

    • 前端实现
    • 后端实现,需要用到Java的图片类,生成一个图片
	@Override
    protected void doGet(HttpServletRequest req,IOException {
        //如何让浏览器3s刷新一次
        resp.setHeader("refresh","3");

        //在内存中创建一个图片
        BufferedImage image = new BufferedImage(100,20,BufferedImage.TYPE_INT_RGB);
        //得到图片
        Graphics2D g = (Graphics2D) image.getGraphics();    //笔
        //设置图片的背景颜色
        g.setColor(Color.white);
        g.fillRect(0,100,20);
        //给图片写数据
        g.setColor(Color.blue);
        g.setFont(new Font(null,Font.BOLD,20));
        g.drawString(makeNum(),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(99999999) + "";
        StringBuffer sb = new StringBuffer();
        //防止数字不满8位,空位用0填充
        for (int i = 0; i < 7 - num.length(); i++) {        //快捷键 fori
            sb.append("0");
        }
        String s = sb.toString() + num;
        return num;
    }
  • 4.实现重定向

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

常见场景:

  • 用户登录
    void sendRedirect(String var1) throws IOException;

测试

    @Override
    protected void doGet(HttpServletRequest req,IOException {
        /*重定向的原理
        resp.setHeader("Location","/response/img");
        resp.setStatus(302)
         */
        resp.sendRedirect("/response/img");     //重定向
    }

面试题:请你聊聊重定向和转发的区别

相同点

  • 页面都会跳转

不同点

  • 请求转发的时候。url不会产生变化 307
  • 重定向的时候,url地址栏会发生变化 302
  • 原理图如下

https://www.52php.cn/res/2020/11-24/11/bf5b922658ace152dc2827ba2f261243.png

request重定向

@Override
protected void doGet(HttpServletRequest req,IOException {
    //处理请求
    String username = req.getParameter("username");
    String password = req.getParameter("password");

    System.out.println(username + ":" + password);

    //重定向时候一定要注意,路径问题,否则404
    resp.sendRedirect("/response/success.jsp");
}

index.jsp

<html>
<body>
<h2>Hello World!</h2>

<%--这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的的项目--%>
<form action="${pageContext.request.contextPath}/login" method="get">
    用户名:<input type = "text" name="username">
    密码:<input type="password" name="password">
    <input type="submit">
</form>


</body>
</html>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Success</title>
</head>
<body>
<h2>Success</h2>
</body>
</html>

7. HttpServletRequset

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

获取参数,并请求转发

@Override
protected void doGet(HttpServletRequest req,IOException {
    //后台接受中文乱码问题
    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");

    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String[] hobbies = req.getParameterValues("hobbies");
    System.out.println("===================================");
    System.out.println(username);
    System.out.println(password);
    System.out.println(Arrays.toString(hobbies));
    System.out.println("===================================");

    //通过请求转发
    System.out.println(req.getContextPath());
    //说明:转发是内部资源,写相对路径;重定向是外部资源,写绝对路径
    req.getRequestDispatcher("success.jsp").forward(req,resp);
}

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>

<h1>登录</h1>

<div style="text-align: center">
    <%--这里表单表示的意思:以post方式提交表单,提交到我们的login请求--%>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="text" name="username"> <br>
        密码:<input type="password" name = "password"> <br>
        爱好:
        <input type="checkbox" name = "hobbies" value="女孩">女孩
        <input type="checkbox" name = "hobbies" value="代码">代码
        <input type="checkbox" name = "hobbies" value="唱歌">唱歌
        <input type="checkbox" name = "hobbies" value="电影">电影

        <br>
        <input type="submit">
    </form>
</div>
</body>
</html>

success.jsp

<%--
  Created by IntelliJ IDEA.
  User: a000248
  Date: 2020/7/30
  Time: 11:14
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<h1>登录成功!</h1>

</body>
</html>

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读