JavaWeb学习笔记(二)

笔记整理自狂神说JavaWeb

JavaWeb学习笔记(二)

6、Servlet

6.1、简介

  • servlet是sun公司用来开发动态web的工具
  • sun在API中提供了一个接口叫做 servlet,开发一个servlet程序需要两个步骤
    • 编写一个java类实现servlet接口
    • 把编写好的java类部署到web服务器上

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

6.2、HelloServlet

Servlet接口sun公司提供了两个默认的实现类: HttpServlet,GenericServlet

  • 构建一个普通的Maven项目,删掉里面的src目录,在这个项目里面建立Moudel(模块),这个空的工程就是Maven主工程

  • 在Maven父子工程中

    父项目的pom.xml中自动生成

    <!--读pom文件时,要去读modules下的子pom文件-->
    <modules>
    	<module>HelloServlet</module>
    </modules>
    

    子类项目的pom.xml自动生成

    <!--使子项目继承父项目的设置,避免导入重复依赖 eg:son extends parent-->
    <parent>
        <artifactId>javaweb-02-servlet</artifactId>
        <groupId>com.servlet</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    
    
  • 编写一个Servlet程序

JavaWeb学习笔记(二)

  • 编写一个普通类,实现Servlet接口,这里我们直接继承HttpServlet(HttpServlet实现了Servlet接口

    public class HelloServlet extends HttpServlet {
        @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);
        }
    }
    
  • 编写servlet映射

    我们编写的java程序需要被浏览器访问,而浏览器需要访问web服务器,所以我们需要在web服务器中部署servlet,给他一个访问的具体路径。所以我们在web.xml中注册servlet和servlet-mapping

    <!--注册servlet-->
    <servlet>
    <servlet-name>helloServlet</servlet-name>
    <servlet-class>com.thomas.HelloServlet</servlet-class>
    </servlet>
    <!--每一个servlet对应一个映射-->
    <servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
    </servlet-mapping>
    
  • 配置tomcat

  • 启动项目

6.3、Servlet原理

JavaWeb学习笔记(二)

  • Web Client 向Servlet容器(Tomcat)发出请求
  • Tomcat接收Web Client的请求
  • Servlet容器创建一个HttpResquest对象,将请求的信息封装到对象中
  • Servlet容器创建一个HttpResponse对象
  • Servlet容器调用HttpServlet对象的service(),把httpResquest和httpResponse传给HttpServlet对象
  • HttpServlet调用HttpRequest对象的有关方法,获取http请求的信息
  • HttpServlet调用HttpResponse对象的有关方法,生成响应数据
  • Servlet容器把HttpServlet的响应结果传给Web Client

6.4、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>/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>
    <servlet-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>/hello5</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-mapping>
        <servlet-name>hello</servlet-name>
        <url-pattern>*.cxd</url-pattern>
    </servlet-mapping>
    
  • 优先级问题

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

    <!--404-->
    <servlet>
        <servlet-name>error</servlet-name>
        <servlet-class>com.thomas.servlet.ErrorServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>error</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    

6.5、ServletContext对象

当web容器启动时,会创建一个servletContext对象,可以通过这个对象让servlet之间进行通信,代表当前的web应用

  • 共享数据

    我们在一个Servlet中通过servlerContext对象保存(set)的数据,可以在另一个servlet通过servlerContext对象get到

    public class SetServletContext extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = this.getServletContext();
            String name =  "thomas冯";
    
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            servletContext.setAttribute("username",name);
        }
    }
    
    public class GetServletContext extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            ServletContext servletContext = this.getServletContext();
            String username = (String) servletContext.getAttribute("username");
    
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().print("username : " + username);
        }
    }
    
  • 获取初始化参数

    web.xml

    <!--配置一些web应用初始化参数-->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/mybatis</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);
    }
    
  • 请求转发

    请求转发和重定向的区别

    forward(转发)

    是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,因为这个跳转过程实在服务器实现的,并不是在客户端实现的所以客户端并不知道这个跳转动作,所以它的地址栏还是原来的地址

    redirect(重定向)

    是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL

    转发是服务器行为,重定向是客户端行为

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        System.out.println("进入了sd4");
        RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");//转发的请求路径
        requestDispatcher.forward(req,resp);//调用forward实现请求转发
        //合并写  context.getRequestDispatcher("/gp").forward(req,resp);
    }
    
  • 读取资源文件

    ##properties文件内容
    username=root12312
    password=zxczxczxc
    
    public class ServletDemo05 extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            InputStream is = this.getServletContext().getResourceAsStream("/WEB-INF/classes/com/kuang/servlet/aa.properties");
    
            Properties prop = new Properties();
            prop.load(is);
            String user = prop.getProperty("username");
            String pwd = prop.getProperty("password");
    
            resp.getWriter().print(user+":"+pwd);
    
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            doGet(req, resp);
        }
    }
    

6.6、HttpServletResponse

web服务器接收了web client的请求,生成两个对象:HttpServletResponse和HttpServletRequest

  • response负责把数据传给浏览器
  • request负责读取client请求的信息

使用HttpServletResponse让浏览器下载文件

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取文件路径
    String filePath = "D:\\ForStrong_java\\javaweb\\javaweb-02-servlet\\ServletHttpResponse\\target\\classes\\1.jpg";
    //获取文件名
    String fileName = filePath.substring(filePath.lastIndexOf("\\") + 1);
    //获取文件输入流
    BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
    //获取向浏览器的输出流
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(resp.getOutputStream());
    //让浏览器知道我们要下载文件,需要设置头,让浏览器支持。中文文件名URLEncoder.encode编码,否则有可能乱码
    resp.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"utf-8"));
    //向浏览器输出数据
    byte[] buffer = new byte[1024];
    int len = 0;
    while ((len = bufferedInputStream.read(buffer))>0){
        bufferedOutputStream.write(buffer,0,len);
    }
    //关闭流
    bufferedInputStream.close();
    bufferedOutputStream.close();
}

response实现验证码,三秒刷新一次

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //写一张图片
    BufferedImage bufferedImage = new BufferedImage(80,20,BufferedImage.TYPE_INT_RGB);//需要一张画板
    Graphics graphics = bufferedImage.getGraphics();//需要一只画笔
    //设置背景
    graphics.setColor(Color.white);//设置颜色
    graphics.fillRect(0,0,80,20);
    //设置内容
    graphics.setColor(Color.blue);
    graphics.setFont(new Font(null,Font.ITALIC,20));
    graphics.drawString(Objects.requireNonNull(makeNum()),0,20);

    //告诉浏览器,这个请求用图片的方式打开
    resp.setContentType("image/jpeg");
    //网站存在缓存,不让浏览器缓存
    resp.setDateHeader("expires",-1);
    resp.setHeader("Cache-Control","no-cache");
    resp.setHeader("Pragma","no-cache");
    //给这个响应设置三秒刷新一次,且把缓存机制关掉
    resp.setHeader("refresh","3");
    //将这张图片写入浏览器
    ImageIO.write(bufferedImage,"jpg",resp.getOutputStream());
}

response实现重定向

//参数为:项目名/地址名
resp.sendRedirect("/ServletHttpResponse/getImage");
<%--action:这里提交的路径,需要寻找到项目的路径--%>
<%--${pageContext.request.contextPath}代表当前的项目--%>
<form action="${pageContext.request.contextPath}/redirect" method="get">
    username <input name="username" type="text"> <br>
    password: <input name="password" type="password"> <br>
    <input type="submit">
</form>
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    System.out.println(username +":  "+password);
    //参数为:项目名/地址名
    resp.sendRedirect("/ServletHttpResponse/success.jsp");
}

6.7、HttpServletRequest

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

request获取请求的数据,并请求转发

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[] hobbies = req.getParameterValues("hobbies");
    System.out.println(username);
    System.out.println(password);
    System.out.println(Arrays.toString(hobbies));

    //请求转发
    req.getRequestDispatcher("/success.jsp").forward(req,resp);
}
<form action="${pageContext.request.contextPath}/login" method="post">
    username <input name="username" type="text"> <br>
    password: <input name="password" type="password"> <br>
    hobbies:
    <input name="hobbies" type="checkbox" value="女孩">女孩
    <input name="hobbies" type="checkbox" value="代码">代码
    <input name="hobbies" type="checkbox" value="电影">电影
    <input name="hobbies" type="checkbox" value="爬山">爬山
    <input type="submit">
</form>

7、Cookie、Session

7.1、会话

  • 会话:用户打开一个浏览器,点击了很多超链接,访问多个web资源,关闭浏览器,这个过程可以称之为会话
  • 有状态会话:一个同学来过教室,下次再来教室,我们会知道这个同学,曾经来过,称之为有状态会话
  • 一个网站,怎么证明你来过?
    • 客户端 服务端
      • 服务端给客户端一个 信件,客户端下次访问服务端带上信件就可以了(cookie)
      • 服务器登记你来过了,下次你来的时候我来匹配你(seesion)

7.2、保存会话的两种技术

cookie

  • 客户端技术 (响应,请求)

session

  • 服务器技术,利用这个技术,可以保存用户的会话信息? 我们可以把信息或者数据放在Session中

7.3、Cookie

JavaWeb学习笔记(二)

  • 从请求中拿到cookie信息

  • 服务器响应给客户端cookie

    Cookie[] cookies = req.getCookies(); //获得Cookie
    cookie.getName(); //获得cookie中的key
    cookie.getValue(); //获得cookie中的vlaue
    new Cookie("lastLoginTime", System.currentTimeMillis()+""); //新建一个cookie
    cookie.setMaxAge(24*60*60); //设置cookie的有效期
    resp.addCookie(cookie); //响应给客户端一个cookie
    

cookie:一般会保存在本地的 用户目录下 appdata

一个网站cookie是否存在上限

  • 一个Cookie只能保存一个信息
  • 一个web站点可以给浏览器发送多个cookie,最多存放20个cookie
  • Cookie大小有限制4kb
  • 300个cookie浏览器上限

删除Cookie

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

编码解码

URLEncoder.encode("测试","utf-8")
URLDecoder.decode(cookie.getValue(),"UTF-8")

7.4、Session

JavaWeb学习笔记(二)

什么是Session:

  • 服务器会给每一个用户(浏览器)创建一个Seesion对象;
  • 一个Seesion独占一个浏览器,只要浏览器没有关闭,这个Session就存在;
  • 用户登录之后,整个网站它都可以访问!–> 保存用户的信息;保存购物车的信息……

使用Session

@Override
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("name",new Person("测试",1));
    //获取Session的ID
    String sessionId = session.getId();

    //判断Session是不是新创建
    if (session.isNew()){
        resp.getWriter().write("session创建成功,ID:"+sessionId);
    }else {
        resp.getWriter().write("session以及在服务器中存在了,ID:"+sessionId);
    }

    //Session创建的时候做了什么事情;
//        Cookie cookie = new Cookie("JSESSIONID",sessionId);
//        resp.addCookie(cookie);
}

获得Session

HttpSession session = req.getSession();

Person person = (Person) session.getAttribute("name");

System.out.println(person.toString());

HttpSession session = req.getSession();
session.removeAttribute("name");
//手动注销Session
session.invalidate();

会话自动过期:web.xml配置

<!--设置Session默认的失效时间-->
<session-config>
    <!--15分钟后Session自动失效,以分钟为单位-->
    <session-timeout>15</session-timeout>
</session-config>

7.5 cookie和seesion的异同

  • **相同点: **
  • cookie和session都是为了解决http协议无状态的特征
  • 区别:
    • cookie数据是存放在客户端本地的,session数据是存放在服务器的,但是服务端的session的实现对客户端的cookie有依赖关系的
    • cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session
    • session会在一段时间内存放在服务器,如果session过多,会导致服务器压力过大,性能降低。如果考虑服务器性能方面应该使用cookie
    • session会在一段时间内存放在服务器,如果session过多,会导致服务器压力过大,性能降低。如果考虑服务器性能方面应该使用cookie
    • 一个用户在一个站点上可以有多个cookie,但是只有一个session
上一篇:第一个SpringMVC


下一篇:WEB后端_Day02(HTTP协议、HttpServletRequest、HttpServletResponse、请求转发、Web 中的相对路径和绝对路径、重定向、JavaEE 项目的三层架构)