Servlet学习笔记

Servlet学习笔记

笔记地址:https://github.com/userwusir/study-notes

1、环境搭建

1.1、Maven下载配置

  1. 下载地址:https://maven.apache.org/download.cgiimage-20210312224358846

  2. 配置环境变量

    M2_HOME Maven目录下的bin目录,例:C:\Program Files\Environment\apache-maven-3.6.3\bin

    MAVEN_HOME Maven的目录,例:C:\Program Files\Environment\apache-maven-3.6.3

    在系统Path中配置 %MAVEN_HOME%\bin

  3. 查看是否安装成功

    mvn -v

    image-20210312224942578

  4. 配置阿里云镜像

    打开conf文件夹下的settings.xml文件,找到<mirrors></mirror>,在其中插入代码

    <mirror>
               <id>nexus-aliyun</id>
               <mirrorOf>*,!jeecg,!jeecg-snapshots</mirrorOf>
               <name>Nexus aliyun</name>
               <url>http://maven.aliyun.com/nexus/content/groups/public</url> 
           </mirror>
    

    image-20210312225804332

  5. 本地仓库配置

    找到<localRepository></localRepository>,默认本地仓库在user/.m2/repository下,可以自己新建文件夹设置为本地仓库,例:<localRepository>C:\Program Files\Environment\apache-maven-3.6.3\maven-repo</localRepository>image-20210312225903735

1.2、IDEA中Maven的一些操作

  1. pom.xml文件

    创建一个Maven的示例webapps项目后

    image-20210312230725347

  2. 导入jar包

    jar包地址:https://mvnrepository.com/

    例:需要Servlet的jar包,搜索Servlet,选择自己所需要的jar包,复制这一段内容,在pom.xml中进行配置,Maven会自动配置所需jar包及其所需依赖jar包image-20210312231431151

    image-20210312231531323

  3. 配置Tomcat

    image-20210312231633653

    image-20210312231703422

  4. 运行测试

    image-20210312231833711

2、HelloServlet

2.1、创建项目

image-20210312232213808

2.2、编写pom.xml

文件中导入Servlet的jar包即可

2.3、编写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">
    <!--我们写的是JAVA程序,但是要通过浏览器访问,二浏览器需要连接web服务器,
    所以我们需要在web服务中注册我们写的Servlet,还需给它一个浏览器能够访问的路径-->
    <!--注册Servlet-->
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.wll.servlet.HelloServlet</servlet-class>
    </servlet>
    <!--Servlet的请求路径-->
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
</web-app>

2.4、源程序

package com.wll.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 writer = resp.getWriter();
        writer.print("Hello Servlet !");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

2.5、测试运行

image-20210312234007658

2.6、总结

  1. image-20210312233834351

  2. 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可以指定通用映射路径
    <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可以指定一些后缀或前缀
    <!--可以自定义后缀实现请求映射,*前面不能加项目映射路径-->
    <servlet-mapping>
            <servlet-name>hello</servlet-name>
            <url-pattern>*.wll</url-pattern>
    </servlet-mapping>
    
    • 优先级

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

3、Servlet

3.1、 Servlet运行原理图

image-20210313084929808

3.2、ServletContext

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

    • 共享数据

      我们在这个Servlet中保存的数据,可以在另外一个Servlet中获得,不要存太多,服务器会炸

    image-20210313093803396

    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /*
            this.getInitParameter()   初始化参数
            this.getServletConfig()   Servlet配置
            this.getServletContext()  Servlet上下文
         */
            ServletContext servletContext = this.getServletContext();
            String name = "wll";    //数据
            servletContext.setAttribute("name",name);   //保存数据到ServletContext 键:name 值:name
    
            System.out.println("hello");
        }
    }
    
    public class GetServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = this.getServletContext();
            String name = (String) servletContext.getAttribute("name");
            System.out.println("名字:"+name);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.wll.servlet.HelloServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>getcontext</servlet-name>
        <servlet-class>com.wll.servlet.GetServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>getcontext</servlet-name>
        <url-pattern>/getcontext</url-pattern>
    </servlet-mapping>
    

    image-20210313114348955

    • ​ 获取初始化参数 getInitParameter
        <!--配置web应用的一些初始化参数-->
        <context-param>
            <param-name>jdbc</param-name>
            <param-value>jdbc:mysql://localhost:3306/mybatis</param-value>
        </context-param>
    
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = this.getServletContext();
            String jdbc = servletContext.getInitParameter("jdbc");
            resp.getWriter().print(jdbc);
        }
    

    image-20210313123451439

    • ​ 请求转发
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = this.getServletContext();
    //        RequestDispatcher getparam = servletContext.getRequestDispatcher("/getparam");   //获取请求转发路径
    //        getparam.forward(req,resp); //调用forward实现请求转发
            servletContext.getRequestDispatcher("/getparam").forward(req,resp);
        }
    
        <servlet>
            <servlet-name>getdispatcher</servlet-name>
            <servlet-class>com.wll.servlet.GetDispatcher</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>getdispatcher</servlet-name>
            <url-pattern>/getdispatcher</url-pattern>
        </servlet-mapping>
    

    image-20210313124815106

    • ​ Properties

      在java目录下新建properties文件,在resources目录下新建properties文件,都被打包到了同一个路径下:classes(classpath)

      image-20210313161905041

      user=root
      password=123123
      
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties");
             //InputStream resourceAsStream = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/wll/servlet/ad.properties");
              Properties properties = new Properties();
              properties.load(resourceAsStream);
              String user = properties.getProperty("user");
              String password = properties.getProperty("password");
              resp.getWriter().print(user+password);
          }
      
          <servlet>
              <servlet-name>getproperties</servlet-name>
              <servlet-class>com.wll.servlet.GetProperties</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>getproperties</servlet-name>
              <url-pattern>/getproperties</url-pattern>
          </servlet-mapping>
      

      Maven约定大于配置,如果properties写在java目录下无法导出,所以配置pom.xml文件

      <build>
          <!--在build中配置resources,来防止我们资源导出失败的问题-->
              <resources>
                  <resource>
                      <directory>src/main/resources</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                  </resource>
                  <resource>
                      <directory>src/main/java</directory>
                      <includes>
                          <include>**/*.properties</include>
                          <include>**/*.xml</include>
                      </includes>
                      <filtering>true</filtering>
                  </resource>
              </resources>
      </build>
      

      image-20210313155339639

3.3、HttpServletRequest

  • 获取前端传递的参数&&请求转发
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Login</title>
</head>
<body>
    <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="奥力给">奥力给
        <input type="submit">
    </form>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
    <h1>登录成功</h1>
</body>
</html>
<?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">
    <welcome-file-list>
        <welcome-file>/login.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>request</servlet-name>
        <servlet-class>com.wll.servlet.RequestForward</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>request</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>
</web-app>
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");
        //获取checkbox内容
        String[] hobbies = req.getParameterValues("hobbies");
        System.out.println(username);
        System.out.println(password);
        System.out.println(Arrays.toString(hobbies));
        //请求转发	对比ServletContext请求转发
        req.getRequestDispatcher("/success.jsp").forward(req,resp);
    }
    //post调用了get,虽然submit方式是post,但是直接在get里写就行
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

测试

image-20210315153822471

image-20210315153850433

image-20210315153910708

3.4、HttpServletResponse

  1. 向浏览器输出信息

  2. 下载文件

    1. 获取下载文件的路径
    2. 获取下载的文件名
    3. 设置办法让浏览器能够支持(Content-Disposition)下载我们需要的东西,中文文件名URLEncoder.encode编码,否则有可能乱码
    4. 获取下载文件的输入流
    5. 创建缓冲区
    6. 获取OutputStream对象
    7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端
    8. 关闭流
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
            //1. 获取下载文件的路径
            String realPath = this.getServletContext().getRealPath("\\WEB-INF\\classes\\a.png");
            //2. 获取下载的文件名,subString:截取父字符串的一部分   lastIndexOf:返回此字符在字符串中最后一次出现的位置
            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 fileInputStream = new FileInputStream(realPath);
            //5. 创建缓冲区
            int len = 0;
            byte[] buffer = new byte[1024];
            //6. 获取OutputStream对象
            ServletOutputStream outputStream = resp.getOutputStream();
            //7. 将FileOutputStream流写入到buffer缓冲区,使用OutputStream将缓冲区中的数据输出到客户端
            while((len=fileInputStream.read(buffer))>0){
                outputStream.write(buffer,0,len);
            }
            //8. 关闭流
            fileInputStream.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);
            //得到图片
            Graphics2D graphics2D = (Graphics2D)image.getGraphics();    //笔
            //设置图片背景颜色
            graphics2D.setColor(Color.white);
            graphics2D.fillRect(0,0,80,20);
            //给图片写数据
            graphics2D.setColor(Color.blue);
            graphics2D.setFont(new Font(null,Font.BOLD,18));
            graphics2D.drawString(fun(),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 fun(){
            Random random = new Random();
            String s = random.nextInt(99999999) + "";
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < 8-s.length(); i++) {
                buffer.append("0");
            }
            //保证一定是八位数
            String s1 = buffer.toString() + s;
            return s1;
        }
    

    image-20210313211658177

  4. 实现重定向

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

    常见场景:

    • 用户登录
    public void sendRedirect(String location) throws IOException;
    
    • 重定向和转发的区别

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

      不同点:跳转地址url不会变化,重定向会变化 302

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <html>
    <body>
    <h2>Hello World!</h2>
    <%--这里提交的路径:需要寻找到的项目的路径--%>
    <%--${pageContext.request.contextPath}代表当前项目--%>
    <form action="${pageContext.request.contextPath}/login" method="post">
        用户名:<input type="username" name="username"><br>
        密码:<input type="password" name="password"><br>
        <input type="submit">
    </form>
    </body>
    </html>
    
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <body>
    <h2>Success</h2>
    </body>
    </html>
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            System.out.println(username+" "+password);
            /*
                重定向
                resp.setHeader("location","/response_war/success");
                resp.setStatus(302);
             */
            resp.sendRedirect("/response_war/success.jsp");
        }
    

    image-20210313223331355

    image-20210313223353564

    image-20210313223408737

3.5、Cookie、Session

  1. Cookie

    • 一个网站如何判断用户是否来过

      • 服务端给客户端一个信件,客户端下次访问服务器带上信件就行了:Cookie(客户端技术)
      • 服务器登录用户来过了,下次用户来的时侯服务器匹配用户:Session(服务器技术)
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=UTF-8");
            PrintWriter writer = resp.getWriter();
            //从服务器端从客户端获取cookie
            Cookie[] cookies = req.getCookies();
            if (cookies != null) {
                writer.print("你上一次访问的时间是:");
                for (int i = 0; i < cookies.length; i++) {
                    Cookie cookie = cookies[i];
                    if (cookie.getName().equals("lastLoginTime")) {
                        //获取cookie中的值
                        Long value = Long.parseLong(cookie.getValue());
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                        writer.print(simpleDateFormat.format(value));
                    }
                }
            } else {
                writer.print("这是你第一次访问本网站");
            }
        
            //Cookie lastLoginTime = new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis()));
            //设置有效期为一天
            //lastLoginTime.setMaxAge(24*60*60);
            //resp.addCookie(lastLoginTime);
        
            //第一次访问服务器给客户端响应一个cookie
            resp.addCookie(new Cookie("lastLoginTime", String.valueOf(System.currentTimeMillis())));
        }
    

    image-20210315180609289

    image-20210315180632728

    删除cookie:

    • 不设置有效期,关闭浏览器,自动失效
    • 设置有效期时间为0
  2. Session

    什么是Session:

    • 服务器会给每一个用户(浏览器)创建一个Session对象
    • 一个Session独占一个浏览器,只要浏览器没关,这个Session就存在
    • 用户登陆后,整个网站都可以访问--->B站个人信息管理

    image-20210315203005915

    public class Person {
        private String name;
        private int age;
        private String sex;
    
        public Person(String name, int age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
    
        public Person() {
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", sex='" + sex + '\'' +
                    '}';
        }
    }
    

    SessionTest01

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html;charset=utf-8");
            //获取Session
            HttpSession session = req.getSession();
            //Session中存东西
            session.setAttribute("person", new Person("jack", 18, "男"));
            //获取Session的id
            String sessionId = session.getId();
    
            //Session是不是新建
            if (session.isNew()) {
                resp.getWriter().print("Session创建成功,ID:" + sessionId);
            } else {
                resp.getWriter().print("Session已经创建,ID:" + sessionId);
            }
            //Session创建时候干了什么
            //Cookie cookie = new Cookie("JSESSIONID",sessionId);
            //resp.addCookie(cookie);
        }
    

    SessionTest02

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            req.setCharacterEncoding("utf-8");
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html;charset=utf-8");
            //获取Session
            HttpSession session = req.getSession();
            //获取session 中的数据
            Object person = session.getAttribute("person");
            resp.getWriter().print(person);
        }
    

    SessionTest03

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //手动注销Session,常见场景:用户注销登录,自动注销Session在web.xml文件中配置
            HttpSession session = req.getSession();
            session.removeAttribute("person");
            session.invalidate();
        }
    
    <servlet>
            <servlet-name>session01</servlet-name>
            <servlet-class>com.wll.servlet.SessionTest01</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>session01</servlet-name>
            <url-pattern>/s1</url-pattern>
        </servlet-mapping>
    
        <servlet>
            <servlet-name>session02</servlet-name>
            <servlet-class>com.wll.servlet.SessionTest02</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>session02</servlet-name>
            <url-pattern>/s2</url-pattern>
        </servlet-mapping>
    
        <servlet>
            <servlet-name>session03</servlet-name>
            <servlet-class>com.wll.servlet.SessionTest03</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>session03</servlet-name>
            <url-pattern>/s3</url-pattern>
        </servlet-mapping>
    
        <!--Session自动注销,1分钟-->
        <session-config>
            <session-timeout>1</session-timeout>
        </session-config>
    

    测试

    image-20210315203340640

    image-20210315203357300

    调用s3后直接访问s2为null、s1中sessionid改变

    image-20210315203434013

    image-20210315203525079

  3. 总结

    • Session与Cookie的区别:
      • Cookie是把用户的数据直接写给用户的浏览器,浏览器可以保存(多个)
      • Session把用户的数据写到用户独占的Session中,服务端保存(保存重要的信息,避免服务器资源浪费)
    • Session使用场景
      • 保存一个用户的登录信息
      • 购物车信息
      • 在整个网站中经常使用的数据,保存到Session中
posted @ 2021-03-15 20:42  芜湖男酮  阅读(100)  评论(0)    收藏  举报