JavaWeb——Servlet

          • 请求转发是一次转发
          • 请求转发URL地址不会发生变化,会保留当前Servlet的资源访问路径
          • 共享同一个Request作用域,可用于多页面之间传递数据
    • getServletContext()
      • 返回一个ServletContext()对象
    • 获取请求头信息
      • getHeader(String key)根据key获取value
        • 例如 request.getHeader("User-Agent")
      • getHeaderNames()获取所有请求头名称
        • 返回一个Enumeration<String>对象
          • 类似集合迭代器的对象
            • hasMoreElements()
              • 返回boolean值
              • 判断是否有下一个元素
            • nextElement()
              • 返回下一个元素

      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      response.setContentType("text/html;charset=UTF-8");
      PrintWriter out = response.getWriter();
      Enumeration<String> headerNames = request.getHeaderNames();
      out.println("

      ");
      //Enumeration是一个类似集合迭代器的对象,可以存放多个数据,需要循环获取每个元素对象
      while (headerNames.hasMoreElements()) {
      String head = headerNames.nextElement();
      out.println( head + "=" + request.getHeader(head) + "
      ");
      }
      out.println("

      ");
      }

    • 获取请求网络数据
      • getMethod()
        • 获取网络请求的请求方式
      • getProtocol()
        • 获取网络协议
      • getLocalPort()
        • 获取请求的端口
      • getServletPath()
        • 获取请求资源的路径
        • 如:/servlet
      • getRequestURI()
        • 获取请求的资源路径,包括应用上下文访问路径+请求的资源路径
        • 应用上下文访问路径/请求资源的路径
        • /web01/servlet
      • getRequestURL()
      • getContextPath()
        • 获取应用上下文访问路径
        • /web01
        • 在请求资源路径之前动态获取应用上下文访问路径,避免因为应用上下文访问路径问题导致资源无法访问
          • <a href = "<%=request.getContextPath()%>/servlet">超链接</a>

      //获取请求方式
      String method = request.getMethod();
      out.println("请求方式 =" + method + "
      ");//请求方式 =GET
      //获取请求协议
      String protocol = request.getProtocol();
      out.println("请求协议 =" + protocol + "
      ");//请求协议 =HTTP/1.1
      //获取请求资源的路径
      String servletPath = request.getServletPath();
      out.println("servletPath = " + servletPath + "
      ");//servletPath = /servlet
      //获取请求URI 包括应用上下文对象+请求的资源路径
      String requestURI = request.getRequestURI();
      out.println("URI =" + requestURI + "
      ");//URI =/web01/servlet
      //获取请求URL地址栏完整路径 包括 协议+ip+端口+应用上下文访问路径+请求的资源路径
      StringBuffer requestURL = request.getRequestURL();
      out.println("URL =" + requestURL + "
      ");//URL =http://localhost:8080/web01/servlet
      //获取请求的应用上下文访问路径
      String contextPath = request.getContextPath();
      out.println("contextPath = " + contextPath);//contextPath = /web01

HttpServletResponse用户响应对象

  • 常用方法
    • setCharacterEncoding(String charSet)设置输出编码格式
      • 传入一个String类型的编码格式
    • setContextType("text/html;charset=UTF-8")
      • 设置响应数据的数据类型为html字符串,编码格式为UTF-8
    • getWriter() 返回一个Writer类型的字符输出流对象,利用该对象可以向页面输出文本或Html
      • 不推荐Servlet中进行数据输出,Servlet主要负责逻辑处理
    • setContentLength()
      • 设置响应时的响应数据大小
    • 设置响应头
      • 不支持中文
      • setHeader(String key,String value)
      • setDateHeader(String key,Date value)
      • setIntHeader(String key,int value)
    • sendRedirect(String url)重定向
      • 可以跳转到某url
      • 重定向是2次请求,地址栏会保留重定向的资源地址,不会共享同一个Request Scope(请求作用域)
      • 可以写uri,但是可能会出问题,建议使用url

请求转发与重定向

  • 区别
    • 转发地址栏不变,转发请求1次,转发时不写工程虚拟路径
      • 地址栏不变可防止重复发送请求
    • 重定向地址栏变化,请求2次,重定向要写工程虚拟路径

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      //请求转发
      request.getRequestDispatcher("/servlet03");
      }

      @Override
      protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      //重定向
      resp.sendRedirect(req.getContextPath() + "/servlet03");
      }

  • 应用场景

    • 重定向
      • 登录、购物车结算
    • 请求转发
      • 其余
  • setHeader("Content-Disposition","attachment;filename=" + file.getName())
    • 设置响应头,请求以下载的方式处理,以及下载文件时的默认文件名称
  • response.setContentLength((int)file.length());
    • 设置响应时的响应数据大小(利用文件大小设置)
  • Servlet与JSP的跳转
    • jsp跳Servlet
      • a标签
      • js(location.href='xxx')
      • form表单action属性
    • Servlet跳jsp
      • 重定向:response.sendRedirect(String url)
      • 请求转发: request.getRequestDispatcher(String uri).forward(request,response)
    • servlet跳servlet
      • 推荐重定向

下载功能的实现

复制代码
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //设置响应输出编码格式,避免文件名中文乱码
        response.setContentType("text/html;charset=UTF-8");
        //获取输入流
        //获取响应输出流
        BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());

        File file =new  File(request.getServletContext().getRealPath("/images/img.png"));
        //获取输入流
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));

        //设置响应头,请求以下载的方式处理,以及下载文件时的默认文件名称
        response.setHeader("Content-Disposition","attachment;filename=" + file.getName());

        //设置响应时的响应数据大小(利用文件大小设置)
        response.setContentLength((int)file.length());

        byte[] bytes = new byte[1024];
        int length = 0;
        while ((length = bis.read(bytes)) != -1) {
            bos.write(bytes, 0,length);
        }
        //刷新缓存,数据推送
        bos.flush();
    }

图片验证码的实现

  • 引入的包
    • Hutool

      <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.26</version> </dependency>
  • 后端

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    //定义图形验证码的父接口
    ICaptcha lineCaptcha = null;

    复制代码
      /**创建一个图形验证码对象
       * param1:宽度
       * param2:高度
       * param3:字符数量
       * param4:干扰线条数量
       */
      lineCaptcha = new LineCaptcha(200,80,5,3);
      //验证码生成
      lineCaptcha.createCode();
    
      //获取验证码信息
      //后期我们应该将这个数据存入Session或其他某些其他容器中等待与用户输入的验证码校验
      String code = lineCaptcha.getCode();
    
      //使用输出流输出验证码图片到浏览器
      response.setContentType("text/html;UTF-8");
      ServletOutputStream sos = response.getOutputStream();
      lineCaptcha.write(sos);
      sos.close();

    }

  • 前端

    <body> <form method="post" action="servlet"> 用户名:
    密  码 :
    验证码: <%--利用JSP脚本表达式,在请求资源路径之前通过动态获取应用上下文对象,避免通过应用上下文对象访问路径问题导致资源无法访问--%>
    看不清,换一张
    </form> </body> <script type="text/javascript"> window.onload = function () { document.getElementById("reset").addEventListener("click",function () { //添加单击事件修改img路径,但是链接必须发生变化,因此使用时间戳 document.getElementById("myImg").src = "<%= request.getContextPath() %>/servlet?timeStemp=" + new Date().getTime() }) } /* var reset = function() {
    复制代码
          }*/
    </script>
  • 细节:

    • get请求重新执行要求链接不同,可通过添加时间戳实现

ServletConfig 初始化参数对象

  • 常用方法
    • getInitParameter(String key)
      • 获取xml文件或注解中的初始化参数,返回String
  • 在非init方法中取得ServletConfig对象
    • this.getServletConfig()

ServletContext

  • 常用方法
    • getRealPath(String uri)
      • 获取uri指向资源的绝对路径
        • servletContext().getRealPath("/")
          • 获取根目录真实路径
        • servletContext().getRealPath("/images/img.png")
          • 获取根目录下/images/img.png文件的真实目录

生命周期

  • 注意:
    • 单例模式,整个Tomcat生命周期中,每个Servlet只会被创建一次

a. init()初始化

    • Servlet对象创建完成后被调用,因为Servlet是单例的,所以整个Tomcat生命周期中只会被调用一次

    • 可与初始化参数配合使用,为Servlet类添加成员变量

    • 必须调用super.init(),否则无法为当前类中的init()属性进行赋值,无法调用init方法以外的其他方法获取config对象

      复制代码
      @Override
      public void init(ServletConfig config) throws ServletException {
          //调用super.init(config)当前类中的config属性赋值
          super.init(config);
          name = config.getInitParameter("name");
          age = config.getInitParameter("age");
      }

b. service()请求进入时

    • 每次请求进入Servlet都会执行一次这个方法,用于分析请求是get还是post,根据请求方式帮助我们调用doGet或doPost方法
    • 注意:必须利用super调用父类中的service方法,否则不会进入doGet或doPost()

c. destroy()销毁

    • Servlet销毁时执行,,因为Servlet是单例的,所以整个Tomcat生命周期中只会被调用一次
    • Servlet销毁的时机是Tomcat容器关闭时,用于释放一些资源

d. 初始化参数

ⅰ. 基于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">
    <servlet>
        <servlet-name>servelet</servlet-name>
        <servlet-class>com.wry.servlet.Servlet</servlet-class>
        <init-param>
            <param-name>i</param-name>
            <param-value>1</param-value>
        </init-param>
        <init-param>
            <param-name>j</param-name>
            <param-value>100</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>servelet</servlet-name>
        <url-pattern>/servlet</url-pattern>
    </servlet-mapping>
</web-app>
ⅱ. 取得初始化参数的值
  • 通过成员变量共享属性值
    • Servlet的init方法只会执行一次,Servlet是单例的。非线程安全的,当出现并发访问,共享数据无法保证一致性.在使用Servlet不要定义共享成员变量.

      public class Servlet extends HttpServlet {
      private String name;
      private String age;

      复制代码
      @Override
      public void init(ServletConfig config) throws ServletException {
          name = config.getInitParameter("name");
          age = config.getInitParameter("age");
      }

      }

  • 通过在方法中获取ServletConfig对象获取初始化参数的值

    • 必须在init()方法中调用super.init(config),否则GennericServlet类中的config属性为null,无法获取到ServletConig对象

    • 利用这种方法,既可以获取初始化参数,又可以避免线程安全问题

      public class Servlet extends HttpServlet {

      复制代码
      @Override
      public void init(ServletConfig config) throws ServletException {
          super.init(config);
      }
      
      /**
       * 用于处理get请求
       * @param request
       * @param response
       * @throws ServletException
       * @throws IOException
       */
      @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          response.setCharacterEncoding("UTF-8");
          //利用用户响应对象获取输出流
          PrintWriter out = response.getWriter();
          out.print(("<h1>收到一个get请求</h1>"));
      
          //获取ServletConfig对象
          ServletConfig config = this.getServletConfig();
          //获取name属性值
          String name1 = config.getInitParameter("name");
          out.println(name1);
      }

      }

ⅲ. 设置Servlet值的初始化时机
  • 通过<Servlet>中的<load-on-startup>标签指定创建实值
    • 只要该标签值大于等于1即可在Tomcat启动时创建Servlet对象
    • 如果有多个Servlet需要在启动时创建,可以利用这个数值决定创建顺序,如果数值相同则按照名称排序决定加载顺序
  • 如果是基于注解配置Servlet则需要在@WebServlet注解中指定loadOnStartup来指定Servlet创建时机值,取值为整数类型

    <servlet> <servlet-name>servelet</servlet-name> <servlet-class>com.wry.servlet.Servlet</servlet-class> <init-param> <param-name>name</param-name> <param-value>Zhangsan</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
  • JSP和Servlet的对比

Servlet中虽然可以写标签、css样式等,但使用起来没有在jsp或者html中书写方便。JSP可以做的事情,Servlet同样可以完成,只不过两者侧重点不同:JSP多用于数据展示,Servlet多用于逻辑控制。

相关推荐
考虑考虑3 小时前
Jpa使用union all
java·spring boot·后端
用户3721574261353 小时前
Java 实现 Excel 与 TXT 文本高效互转
java
浮游本尊4 小时前
Java学习第22天 - 云原生与容器化
java
渣哥6 小时前
原来 Java 里线程安全集合有这么多种
java
间彧6 小时前
Spring Boot集成Spring Security完整指南
java
间彧6 小时前
Spring Secutiy基本原理及工作流程
java
Java水解7 小时前
JAVA经典面试题附答案(持续更新版)
java·后端·面试
洛小豆9 小时前
在Java中,Integer.parseInt和Integer.valueOf有什么区别
java·后端·面试
前端小张同学10 小时前
服务器上如何搭建jenkins 服务CI/CD😎😎
java·后端
ytadpole10 小时前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端