关于java:JavaWeb学习笔记02-ServletCookieSession

5次阅读

共计 14372 个字符,预计需要花费 36 分钟才能阅读完成。

Servlet

Servlet 是 sun 公司开发的解决动静 web 的技术

Servlet 有两个默认的实现类:HttpServlet、GenericServlet

开发 Servlet 程序的步骤:

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

实现了 Servlet 接口的 java 程序称为 Servlet

创立 HelloServlet 我的项目

  1. 构建一个一般的 maven 我的项目,删除 src 文件夹,这个空的工程作为 maven 主工程
  2. 引入 servlet jsp 依赖到 pom.xml

    <dependencies>
      <!-- 增加 Servlet 和 JSP 依赖 -->
      <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.1</version>
      </dependency
      <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
      <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.3</version>
      </dependency>
    </dependencies>

    或手动下载 jar 包到文件夹中

    依赖下载地址:https://mvnrepository.com/

  3. 新建 Module 子模块 servlet01(maven-archetype-webapp)

​ 父我的项目中的 java 子项目能够间接应用,反之不能够

​ 问题 1: 子项目 pom 中没有 parent 标签

​ 解决:在子项目的 pom.xml 中手动增加 parent 标签并刷新 maven

  1. <parent>
      <groupId>cn.itxiaoma</groupId>
      <artifactId>HelloMaven</artifactId>
      <version>1.0-SNAPSHOT</version>
    </parent>

    问题 2:子项目 pom 文件有一条横线并变灰

    解决:file –>setting–>maven–>Ignored Files 将清单中对应我的项目的 pom.xml 文件勾销选中

  2. 将 servlet01 中的 web.xml 改为最新,在 main 目录下新建 java 和 resources

    <?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>
  3. 在 java 目录下新建 package 包 cn..itxiaoma.servlet
  4. 在包下新建 java 类 HelloServlet,并实现 Servlet 接口(继承 HttpServlet)

    package cn.itxiaoma.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 HelloServlet extends HttpServlet {
        //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {PrintWriter printWriter = resp.getWriter();
            printWriter.print("Hello Servlet");
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
        }
    }
  5. 编写 Servlet 的映射

    浏览器连贯的是 web 服务,因而须要在 web 服务中注册咱们写的 Servlet,并配置浏览器可能拜访的门路

    <!--  注册 Servlet-->
    <servlet>
      <servlet-name>hello</servlet-name>
      <servlet-class>cn.itxiaoma.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--  Servlet 的申请门路 -->
    <servlet-mapping>
      <servlet-name>hello</servlet-name>
      <url-pattern>/hello</url-pattern>
    </servlet-mapping>
  6. 配置 Tomcat

    Run > Edit Configurations > + > Tomcat Server – Local > Application server: 抉择 Tomcat 目录

    Deployment > + > servlet01:war exploed

    Application Context: /servlet01_war_exploded

  7. 启动测试

    http://localhost:8081/servlet…

    Servlet 原理

  8. 浏览器发送 http 申请 (service) 到 web 容器(Tomcat)
  9. 首次拜访的申请会加载 Servlet 类到内存
  10. web 容器生成申请 (Request) 和响应 (Response) 两个对象,并调用 Servlet 的 service 办法
  11. Request 会从 service 拿到申请,并执行咱们重写的解决办法,失去响应信息传给 Response
  12. web 容器读取响应信息传回浏览器

    Servlet Mapping 问题

    指定映射门路

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

    多映射门路

    <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>

    指定后缀 / 前缀

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

    注:自定义后缀 / 前缀 * 前不能有映射门路

    自定义异样解决 ErrorServlet

    cn/itxiaoma/servlet/ErrorServlet.java

    package cn.itxiaoma.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 pw = resp.getWriter();
         pw.print("<h1>404</h1>");
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
     }
    }

    src/main/webapp/WEB-INF/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">
      <servlet>
     <servlet-name>hello</servlet-name>
     <servlet-class>cn.itxiaoma.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>cn.itxiaoma.servlet.ErrorServlet</servlet-class>
      </servlet>
      <servlet-mapping>
     <servlet-name>error</servlet-name>
     <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>

    优先级问题:制订了固有的映射门路优先级最高,找不到再走默认的映射

    ServletContext 对象

    web 容器在启动的时候,它会为每个 web 程序创立一个 ServletContext 对象,代表以后的 web 利用

    1. 共享数据

    在一个 Servlet 中保留的数据,能够在其余 Servlet 中获取

    web.xml

    <servlet>
      <servlet-name>get</servlet-name>
      <servlet-class>cn.itxiaoma.servlet.GetServlet</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>get</servlet-name>
      <url-pattern>/get</url-pattern>
    </servlet-mapping>

    HelloServlet.java

    package cn.itxiaoma.servlet;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    public class HelloServlet extends HttpServlet {
     //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context= this.getServletContext();
         String username = "Apple";
         context.setAttribute("username", username);
         System.out.println(username);
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
     }
    }

    GetServlet.java

    package cn.itxiaoma.servlet;
    import javax.servlet.ServletContext;
    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 GetServlet extends HttpServlet {
     //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context = this.getServletContext();
         PrintWriter printWriter = resp.getWriter();
         resp.setContentType("text/html");
         resp.setCharacterEncoding("utf-8");
         printWriter.print("Username:" + context.getAttribute("username"));
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
     }
    }
    2. 获取初始化参数

    web.xml

    <context-param>
      <param-name>url</param-name>
      <param-value>jdbc:mysql://localhost:3306/testdb</param-value>
    </context-param>

    HelloServlet.java

    package cn.itxiaoma.servlet;
    import javax.servlet.ServletContext;
    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 HelloServlet extends HttpServlet {
     //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {ServletContext context= this.getServletContext();
         String url = context.getInitParameter("url");
         resp.getWriter().print(url);
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
     }
    }
    3. 申请转发
    ServletContext context= this.getServletContext();
    RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");// 转发的申请门路
    requestDispatcher.forward(req, resp);
    4. 读取资源文件

    resources 文件夹下新建 db.properties(会打包到 classes 门路下,称为 classpath)

    username=root
    password=123456

    读取资源文件

    ServletContext context= this.getServletContext();
    InputStream inputStream = context.getResourceAsStream("/WEB-INF/classes/db.properties");
    Properties properties = new Properties();
    properties.load(inputStream);
    String username = properties.getProperty("username");
    String password = properties.getProperty("password");
    resp.getWriter().print(username + password);

    HttpServletResponse

    web 服务器接管到客户端的 http 申请,针对这个申请,分表创立一个代表申请的 HttpServletRequest 对象,和一个代表响应的 HttpServletResponse 对象

    javax/servlet/ServletResponse.java

    负责向浏览器发送数据的办法
    public ServletOutputStream getOutputStream() throws IOException;
    public PrintWriter getWriter() throws IOException;
    负责向浏览器发送响应头的办法
    public void setCharacterEncoding(String charset);
    public void setContentLength(int len);
    public void setContentLengthLong(long len);
    public void setContentType(String type);
    常见利用
  13. 向浏览器输入音讯
  14. 下载文件

    1. 获取下载文件门路,文件名
    2. 获取下载文件的输出流
    3. 创立缓冲区
    4. 获取 OutputStream 对象
    5. 将 FileOutputStream 流写入 Buffer 缓冲区
    6. 应用 OutputStream 将缓冲区中的数据输入到客户端
    String realPath = "/Users/4wheels/Downloads/test.jpg";
    String filename = realPath.substring(realPath.lastIndexOf("/") + 1);
    resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
    // 获取文件输出流
    FileInputStream inputStream = new FileInputStream(realPath);
    // 缓冲区
    int len = 0;
    byte[] buffer = new byte[1024];
    ServletOutputStream servletOutputStream = resp.getOutputStream();
    while ((len = inputStream.read(buffer)) > 0) {servletOutputStream.write(buffer, 0, len);
    }
    inputStream.close();
    servletOutputStream.close();
  15. 验证码性能

    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);
        // 绘制图片
        Graphics2D g = (Graphics2D) image.getGraphics();
        g.setColor(Color.white);
        g.fillRect(0, 0, 80, 20);// 绘制填色矩形
        g.setColor(Color.BLACK);
        g.setFont(new Font(null, Font.BOLD, 20));
        g.drawString(makeNum(), 2, 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 sb = new StringBuffer();
        for (int i = 0; i < 7 - num.length(); i++) {sb.append("0");
        }
        num = sb.toString() + num;
        return num;
    }
  16. 重定向

    resp.sendRedirect("/test");

    HttpServletRequest

    解决登录申请
    <html>
    <body>
    <form action="${pageContext.request.contextPath}/login" method="post">
     Username<input type="text" name="username"/><br>
     Password<input type="password" name="password"/><br>
     Hobby<input type="checkbox" name="hobby" value="1"/>
     <input type="checkbox" name="hobby" value="2"/>
     <input type="checkbox" name="hobby" value="3"/>
     <input type="submit"/>
    </form>
    </body>
    </html>

    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">
      <servlet>
     <servlet-name>login</servlet-name>
     <servlet-class>cn.itxiaoma.servlet.LoginServlet</servlet-class>
      </servlet>
      <servlet-mapping>
     <servlet-name>login</servlet-name>
     <url-pattern>/login</url-pattern>
      </servlet-mapping>
    </web-app>

    LoginServlet.java

    package cn.itxiaoma.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.util.Arrays;
    public class LoginServlet extends HttpServlet {
     //get 和 post 只是申请实现的不同形式,业务逻辑一样,因而能够相互调用
     @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[] hobby = req.getParameterValues("hobby");
         System.out.println(username);
         System.out.println(password);
         System.out.println(Arrays.toString(hobby));
    //        req.getRequestDispatcher("/success.jsp").forward(req, resp);
     }
     @Override
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);
     }
    }

    Cookie

  17. cookie 只能保留字符串,不能保留对象
  18. 一个 cookie 只能保留一个信息,最大 4kb
  19. 一个 web 站点能够给浏览器发送多个 cookie,一个站点最多 20 个
  20. 浏览器最多存 300 个左右 cookie
  21. cookie 不设置有效期或设为 0,敞开浏览器主动生效

    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    PrintWriter printWriter = resp.getWriter();
    Cookie[] cookies = req.getCookies();
    if (cookies != null) {printWriter.print("Last Time:");
     for (int i = 0; i < cookies.length; i++) {Cookie cookie = cookies[i];
         if (cookie.getName().equals("lastLoginTime")) {long lastLoginTime = Long.parseLong(cookie.getValue());
             Date date = new Date(lastLoginTime);
             printWriter.write(date.toLocaleString());
         }
     }
    } else {printWriter.print("First Visit.");
    }
    Cookie cookie = new Cookie("lastLoginTime", System.currentTimeMillis()+"");
    resp.addCookie(cookie);

    Session

    服务器会给每个用户(浏览器)创立一个 Session,只有浏览器没有敞开,session 就存在

    Session 和 Cookie 的区别:Cookie 由客户端创立在浏览器保留,Session 在服务器端创立和保留

    Session 和 ServletContext 区别:ServletContext 作用域是全局(Web 利用),Session 作用域是会话(浏览器)

    <servlet>
      <servlet-name>setSession</servlet-name>
      <servlet-class>cn.itxiaoma.servlet.SetSession</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>setSession</servlet-name>
      <url-pattern>/set</url-pattern>
    </servlet-mapping>
    <servlet>
      <servlet-name>getSession</servlet-name>
      <servlet-class>cn.itxiaoma.servlet.GetSession</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>getSession</servlet-name>
      <url-pattern>/get</url-pattern>
    </servlet-mapping>
    <servlet>
      <servlet-name>delSession</servlet-name>
      <servlet-class>cn.itxiaoma.servlet.DelSession</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>delSession</servlet-name>
      <url-pattern>/del</url-pattern>
    </servlet-mapping>
    <!--  设置 session 默认生效工夫 -->
    <session-config>
      <!-- 15 分钟后主动生效 -->
      <session-timeout>15</session-timeout>
    </session-config>

    SetSession.java

    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    PrintWriter printWriter = resp.getWriter();
    HttpSession session = req.getSession();
    session.setAttribute("name", "test");
    String sessionId = session.getId();
    if (session.isNew()) {printWriter.write("Session 创立胜利,Id:" + sessionId);
    } else {printWriter.write("Session 已存在,Id:" + sessionId);
    }

    GetSession.java

    req.setCharacterEncoding("utf-8");
    resp.setCharacterEncoding("utf-8");
    resp.setContentType("text/html;charset=utf-8");
    PrintWriter printWriter = resp.getWriter();
    HttpSession session = req.getSession();
    String sessionId = session.getId();
    String sessionName = (String) session.getAttribute("name");
    printWriter.write("Session Id:" + sessionId);
    printWriter.write("Session Name:" + sessionName);

    DelSession.java

    HttpSession session = req.getSession();
    // 删除指定 session
    session.removeAttribute("name");
    // 手动登记 session
正文完
 0