request&response


typora-copy-images-to: img

request&response

学习目标

第一章-request

知识点-request概述

1.目标

  • 知道什么是request以及作用

2.讲解

2.1什么是request
在Servlet API中,定义了一个HttpServletRequest接口,它继承自ServletRequest接口,专门用来封装HTTP请求消息。由于HTTP请求消息分为请求行、请求头和请求体三部分,因此,在HttpServletRequest接口中定义了获取请求行、请求头和请求消息体的相关方法.

在这里插入图片描述

​ Web服务器收到客户端的http请求,会针对每一次请求,分别创建一个用于代表请求的request对象、和代表响应的response对象。

2.2request作用
  • 操作请求三部分(行,头,体)
  • 请求转发
  • 作为域对象存数据

3.小结

  1. request代表请求对象. 原型是HttpServletRequest, 服务器创建好的, 以形参的方式存在doGet()/doPost()方法里面
  2. Request作用
    • 操作请求的三部分(行,头,体)
    • 转发
    • 作为域对象存取数据

知识点-操作请求行和请求头

1.目标

  • 掌握使用request对象获取客户机信息(操作请求行)和获得请求头信息(操作请求头)

2.路径

  • 获取客户机信息(操作请求行)
  • 获得请求头信息(操作请求头)

3.讲解

3.1获取客户机信息(操作请求行)

​ 请求方式 请求路径(URI) 协议版本

​ GET /day17Request/WEB01/register.htm?username=zs&password=123456 HTTP/1.1

  • getMethod();获取请求方式
  • getRemoteAddr() ;获取客户机的IP地址(知道是谁请求的)
  • getContextPath(); 获得当前应用工程名(部署的路径);
  • getRequestURI();获得请求地址,不带主机名
  • getRequestURL();获得请求地址,带主机名
  • getServerPort();获得服务端的端口
  • getQueryString();获的请求参数(get请求的,URL的?后面的. eg:username=zs&password=123456)
/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  08:58
 * 获取请求行的信息
 */
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用request对象获取请求行的信息:
        //1. 获取请求的方式(可能会用)
        String method = request.getMethod();
        //System.out.println("请求方式为:" + method);

        //2. 获取客户端的ip地址
        String remoteAddr = request.getRemoteAddr();
        //System.out.println("客户端的ip地址是:" + remoteAddr);

        //3. 获取项目部署的路径(以后可能用到)
        String contextPath = request.getContextPath();
        //System.out.println("项目部署路径是:" + contextPath);

        //4. 获取请求的url: 统一资源定位符 http://localhost:8080/requestDemo/demo01
        String url = request.getRequestURL().toString();
        //System.out.println("此次请求的url是:" + url);

        //5. 获取请求的uri: 统一资源标识符,在url的基础上省略了服务器路径"http://loaclhost:8080"
        String uri = request.getRequestURI();
        System.out.println(uri);
    }
}
3.2.获得请求头信息(操作请求头)

请求头: 浏览器告诉服务器自己的属性,配置的, 以key value存在, 可能一个key对应多个value

在这里插入图片描述

getHeader(String name);

  • User-Agent: 浏览器信息
  • Referer:来自哪个网站(防盗链)
/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  09:14
 * 使用request获取请求头的信息
 */
@WebServlet("/demo02")
public class ServletDemo02 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //根据请求头的name获取value
        //目标:获取name为user-agent的请求头的信息
        String header = request.getHeader("user-agent");
        System.out.println("获取的请求头agent为:" + header);
    }
}

4.小结

  1. 操作请求行(获得客户机信息)
    • getMethod(); 获得请求方式
    • getRemoteAddr(); 获得客户机的IP地址
    • getContextPath(); 获得项目的部署的路径
    • getRequestURI(); 获得URI(不带http,主机,端口)
    • getRequestURL(); 获得URL(带http,主机,端口)
  2. 操作请求头
    • getHeader(String name);
      • User-Agent: 浏览器信息
      • Referer:来自哪个网站(防盗链)

知识点-操作请求体(获得请求参数)【重点】

1.目标

  • 掌握获得请求参数, 以及乱码的解决

2.路径

  • 获得请求参数
  • 请求参数乱码的处理
  • 使用BeanUtils封装请求参数到JavaBean

3.讲解

3.1获得请求参数
法名描述
String getParameter(String name)获得指定参数名对应的值。如果没有则返回null,如果有多个获得第一个。 例如:username=jack
String[] getParameterValues(String name)获得指定参数名对应的所有的值。此方法专业为复选框提供的。 例如:hobby=抽烟&hobby=喝酒&hobby=敲代码
Map<String,String[]> getParameterMap()获得所有的请求参数。key为参数名,value为key对应的所有的值。
3.2 请求参数乱码处理

​ 我们在输入一些中文数据提交给服务器的时候,服务器解析显示出来的一堆无意义的字符,就是乱码。
那么这个乱码是如何出现的呢?如下图所示:

在这里插入图片描述

  1. get方式, 我们现在使用的tomcat>=8.0了, 乱码tomcat已经处理好了
  2. post方式, 就需要自己处理
void setCharacterEncoding(String env); //设置请求体的编码
/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  09:33
 * 使用request获取请求参数
 *
 * 请求参数的乱码问题:
 * 在tomcat8之前,无论是get请求还是post请求,请求参数都会发生乱码
 * 在tomcat8之后(包含8),只有post请求才会发生中文乱码
 *
 * 怎么解决乱码: 只要在获取请求参数之前,调用request.setCharacterEncoding(UTF-8);
 */
@WebServlet("/demo03")
public class ServletDemo03 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        //1. 根据参数名,获取一个参数值
        String username = request.getParameter("username");
        //System.out.println("获取的请求参数username=" + username);

        //2. 根据参数名,获取多个参数值:比如说注册时候的兴趣爱好的复选框
        String[] hobbies = request.getParameterValues("hobby");
        /*for (String hobby : hobbies) {
            System.out.println(hobby);
        }*/

        //3. 获取所有的请求参数
        //getParameterMap()获取所有请求参数,请求参数的参数名就是map的key,请求参数的参数值就是map的value
        Map<String, String[]> parameterMap = request.getParameterMap();
        //遍历出每一个请求参数
        Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();
        for (Map.Entry<String, String[]> entry : entries) {
            String parameterName = entry.getKey();
            String[] values = entry.getValue();
            for (String value : values) {
                System.out.println("参数名:" + parameterName + ",参数值:" + value);
            }
        }
    }
}
3.3使用BeanUtils封装

​ 现在我们已经可以使用request对象来获取请求参数,但是,如果参数过多,我们就需要将数据封装到对象。

​ 以前封装数据的时候,实体类有多少个字段,我们就需要手动编码调用多少次setXXX方法,因此,我们需要BeanUtils来解决这个问题。

​ BeanUtils是Apache Commons组件的成员之一,主要用于简化JavaBean封装数据的操作。

使用步骤:

  1. 导入jar
  2. 使用BeanUtils.populate(user,map)
  • 表单
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <form action="/requestDemo/demo04" method="post">
        用户名<input type="text" name="username"><br>
        密码<input type="text" name="password"><br>
        性别<input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
        兴趣爱好
        <input type="checkbox" name="hobby" value="basketball">篮球
        <input type="checkbox" name="hobby" value="football">足球
        <input type="checkbox" name="hobby" value="ppball">乒乓球
        <input type="checkbox" name="hobby" value="yumaoball">羽毛球
        <br>
        <input type="submit" value="注册">
    </form>
</body>
</html>
  • User
/**
 * 包名:com.itheima.pojo
 *
 * @author Leevi
 * 日期2020-07-12  10:19
 */
public class User implements Serializable {
    private String username;
    private String password;
    private String gender;
    private String[] hobby;

    public User() {
    }

    public User(String username, String password, String gender, String[] hobby) {
        this.username = username;
        this.password = password;
        this.gender = gender;
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", hobby=" + Arrays.toString(hobby) +
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }
}
  • ServletDemo04
/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  10:18
 * 我们使用request.getParameterMap()方法获取所有请求参数,是封装在map对象中
 *
 * 我的需求是将获取到的所有请求参数封装到POJO对象中
 * 1. 创建一个POJO类,类中的属性名要和请求参数名对应
 * 2. 使用BeanUtils框架,将map中的数据封装到POJO对象中
 */
@WebServlet("/demo04")
public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        //1. 获取所有的请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        //2. 将请求参数封装到User对象中
        User user = new User();
        //3. 使用BeanUtils框架自动将map中的数据封装到对象中
        try {
            BeanUtils.populate(user,parameterMap);

            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.小结

  1. 获取请求参数的方法

    1. getParameter(name),根据参数名获取一个参数值
    2. getParameterValues(name),根据参数名获取多个参数值
    3. getParameterMap(),获取所有的请求参数封装到map中
  2. 使用BeanUtils封装

    • 如果请求参数有多个需要封装到JavaBean里面, 建议先获得Map, 再使用BeanUtils封装到JavaBean对象

    注意: JavaBean属性需要和Map的key一致 说白了也就是JavaBean属性需要和表单的name一致

  3. 解决请求参数的中文乱码问题

    1. Tomcat8之后,使用get方式提交的请求参数不会发生中文乱码
    2. 解决post请求中的中文参数乱码问题:在获取请求参数之前添加一句代码:request.setCharacterEncoding(“UTF-8”)

知识点-请求转发【重点】

1.目标

  • 掌握请求转发

2.讲解

request.getRequestDispatcher(url).forward(request, response);//转发

3.小结

  • 请求转发的作用:跳转页面,比如说添加完数据之后跳转到数据的展示页面,删除完数据之后跳转到展示页面
  • 请求转发的代码
request.getRequestDispatcher("转发的路径").forward(request,response); 
  • 请求转发的特征
    • 跳转操作是由服务器执行的,所以客户端地址栏不会发生变化
    • 跳转操作不会发起新的请求
    • 可以跳转到WEB-INF中的资源,但是不能跳转到其它项目的资源

知识点-作为域对象存取值

1.目标

  • 掌握requet作为域对象存取值

2.讲解

​ ServletContext: 范围 整个应用(无论多少次请求,只要是这个应用里面的都是可以共享的)

​ request范围: 一次请求有效

​ 域对象是一个容器,这种容器主要用于Servlet与Servlet/JSP之间的数据传输使用的。

  • Object getAttribute(String name) ;
  • void setAttribute(String name,Object object) ;
  • void removeAttribute(String name) ;

3.小结

  1. 作为域对象存取数据

    • Object getAttribute(String name) ; 取
    • void setAttribute(String name,Object object) ; 存
    • void removeAttribute(String name) ; 移除
  2. 范围: 一次请求有效(转发可以使用)

在这里插入图片描述

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  10:50
 * request作为域对象在不同的Servlet之间进行数据的共享,它只能在同一次请求中进行数据共享
 *
 * request域对象只有和请求转发一起使用才有意义
 */
@WebServlet("/demo06")
public class ServletDemo06 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 目标: 在ServletDemo07中获取ServletDemo06中的变量username的值
        // 要求只能是由ServletDemo06跳转到ServletDemo07的时候才能获取
        String username = "周杰棍";

        //将username存储到request域对象中
        request.setAttribute("name",username);

        //请求转发跳转到ServletDemo07
        request.getRequestDispatcher("/demo07").forward(request, response);
    }
}

ServletDemo07的代码

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  10:52
 */
@WebServlet("/demo07")
public class ServletDemo07 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //使用request域对象中取出name的值
        System.out.println("在ServletDemo07中获取username的值:"+request.getAttribute("name"));
    }
}

Request部分的小结

  1. 获取请求行的信息
    1. 获取请求方式:getMethod() 掌握
    2. 获取请求的客户端的ip地址:getRemoteAddr() 掌握
    3. 获取项目部署的路径:getContextPath() 掌握
    4. 获取uri:统一资源标识符 掌握
    5. 获取url:统一资源定位符
    6. 获取服务器的端口号(了解)
    7. 获取请求参数的字符串:getQueryString() (了解)
  2. 获取请求头的信息:getHeader(name) 掌握
  3. 获取请求参数(全部要掌握,最重要)
    1. getParameter(name)
    2. getParameterValues(name)
    3. getParameterMap()
  4. 使用BeanUtils将map中的数据存储到JavaBean对象中(掌握)
    1. map的key要和JavaBean的属性名保持一致,如果不一致那么该字段的值就无法存储
    2. BeanUtils中默认内置一些基本类型的转换器(如果map中的数据是string类型,JavaBean的属性还是int类型那么会自动转换)
  5. 使用request做请求转发: request.getRequestDispatcher(“跳转路径”).forward(request,response); 掌握
  6. request对象作为域对象向存取数据,它的作用范围是一次请求中,和请求转发一起使用 掌握

第二章-Response

知识点-Response概述

1. 目标

  • 掌握什么是Response,以及Response的作用

2. 讲解

2.1 HttpServletResponse概述

​ 在Servlet API中,定义了一个HttpServletResponse接口(doGet,doPost方法的参数),它继承自ServletResponse接口,专门用来封装HTTP响应消息。由于HTTP响应消息分为响应行、响应头、响应体三部分,因此,在HttpServletResponse接口中定义了向客户端发送响应状态码、响应头、响应体的方法

2.2作用
  • 操作响应的三部分(响应行,响应头,响应体)

3.小结

  1. Response代表响应对象. 原型是HttpServletResponse, 服务器创建的, 以形参的形式存在doGet()/doPost()方法
  2. Response的作用
    • 操作响应的三部分(行, 头, 体)

知识点-操作响应行

1.目标

  • 掌握操作响应行的方法

2.讲解

HTTP/1.1 200

在这里插入图片描述

​ 常用的状态码:

​ 200:成功

​ 302:重定向

​ 304:访问缓存

​ 404:客户端错误

​ 500:服务器错误

3.小结

  1. 设置的API: response.setStatus(int code);

  2. 一般不需要设置, 可能302 重定向需要设置

  3. 常见的响应状态码

    • 200 成功
    • 302 重定向
    • 304 读缓存
    • 404 客户端错误
    • 500 服务器错误

知识点-操作响应头

1.目标

  • 掌握操作响应头的方法, 能够进行定时刷新和重定向

2.路径

  • 操作响应头的API介绍
  • 定时刷新
  • 重定向

3.讲解

3.1操作响应头的API

响应头: 是服务器指示浏览器去做什么

​ 一个key对应一个value

在这里插入图片描述

​ 一个key对应多个value
在这里插入图片描述

关注的方法: setHeader(String name,String value);

​ 常用的响应头

​ Refresh:定时跳转 (eg:服务器告诉浏览器5s之后跳转到百度)

​ Location:重定向地址(eg: 服务器告诉浏览器跳转到xxx)

​ Content-Disposition: 告诉浏览器下载

​ Content-Type:设置响应内容的MIME类型(服务器告诉浏览器内容的类型)

3.2 定时刷新
response.setHeader("refresh","秒数;url=跳转的路径"); //几秒之后跳转到指定的路径上
3.3 重定向【重点】

在这里插入图片描述

  1. 重定向两次请求
  2. 重定向的地址栏路径改变
  3. 重定向的路径写绝对路径(带域名/ip地址的, 如果是同一个项目里面的,域名/ip地址可以省略)
  4. 重定向的路径可以是项目内部的,也可以是项目以外的(eg:百度)
  5. 重定向不能重定向到WEB-INF下的资源
  6. 把数据存到request里面, 重定向不可用
//方式一: 重定向
//1.设置状态码
//response.setStatus(302);
//2.设置重定向的路径(绝对路径,带域名/ip地址的,如果是同一个项目里面的,域名/ip地址可以省略)
//response.setHeader("Location","http://localhost:8080/day28/demo08");
//response.setHeader("Location","/day28/demo08");
//response.setHeader("Location","http://www.baidu.com");

//方式二:  直接调用sendRedirect方法, 内部封装了上面两行
response.sendRedirect("http://localhost:8080/day28/demo08");
  • 重定向
 response.sendRedirect("重定向的路径");

重定向和请求转发的对比

在这里插入图片描述

重定向的特点:
  1. 重定向的跳转是由浏览器发起的,在这个过程中浏览器会发起两次请求
  2. 重定向跳转可以跳转到任意服务器的资源,但是无法跳转到WEB-INF中的资源
  3. 重定向跳转不能和request域对象一起使用
  4. 重定向跳转浏览器的地址栏中的地址会变成跳转到的路径
请求转发的特点:
1. 请求转发的跳转是由服务器发起的,在这个过程中浏览器只会发起一次请求
2. 请求转发只能跳转到本项目的资源,但是可以跳转到WEB-INF中的资源
3. 请求转发可以和request域对象一起使用

4.小结

4.1操作响应头

知识点-操作响应体

1.目标

  • 掌握操作响应体以及响应乱码的解决

2.步骤

  • 操作响应体的API介绍
  • 响应乱码的解决

3.讲解

操作响应体的API

在这里插入图片描述

​ 页面输出只能使用其中的一个流实现,两个流是互斥的.

3.1 使用字符输出流输出字符串
  • 解决字符流输出中文乱码问题
response.setContentType("text/html;charset=utf-8");
  • 使用字符输出流
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  12:12
 * response设置响应体的信息
 * 直接给浏览器要展示的数据
 *
 * 解决响应体的乱码问题
 * response.setContentType("text/html;charset=UTF-8");
 * 这句代码底层做了什么?
 * 1. 设置服务器响应的字符集为UTF-8
 * 2. 设置Content-Type响应头的信息为 "text/html;charset=UTF-8"
 *    让浏览器知道了服务器的响应字符集UTF-8,那么浏览器也会使用UTF-8解码
 */
@WebServlet("/demo04")
public class ServletDemo04 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");

        //要向浏览器输出响应体的信息,需要通过流来进行操作
        //第一种:字符串,输出文本内容
        PrintWriter writer = response.getWriter();
        //使用字符流往浏览器输出文本
        //1. writer()方法,只能输出字符串,如果输出int、float等等类型的话,则会有问题
        writer.write("你好世界");

        //2. print()方法,可以输出数字、字符串
        //writer.print(8);
    }
}
3.2 使用字节输出流向浏览器输出文件

目标是:向浏览器输出一张图片

注意:需要引入commons-io的jar包

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  14:29
 * 使用response的字节流向浏览器输出一个文件(一张图片)
 * 目标:浏览器访问ServletDemo05,会在浏览器上显示一张图片
 */
@WebServlet("/demo05")
public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 读取b.jpg图片,将其转换成字节输入流,使用ServletContext
        ServletContext servletContext = getServletContext();
        InputStream is = servletContext.getResourceAsStream("b.jpg");

        //2. 使用字节输出流,将is中的字节都输出到浏览器
        ServletOutputStream os = response.getOutputStream();

        /*byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = is.read(buffer)) != -1){
            os.write(buffer,0,len);
        }*/

        IOUtils.copy(is,os);

        os.close();
        is.close();
    }
}

response部分的总结

  1. 设置响应状态码:setStatus()
  2. 设置响应头:setHeader(name,value)
    1. refresh响应头,用于隔几秒钟之后跳转到某个页面
    2. location响应头,用于重定向到某个页面
  3. 重定向的写法: sendRedirect(地址)
  4. 设置响应体的内容
    1. 使用字符输出流输出文本内容
      1. response.getWriter()获取字符输出流
      2. writer.write()/print()输出字符串
      3. 解决响应数据的中文乱码:response.setContentType(“text/html;charset=UTF-8”)
    2. 使用字节输出流输出文件
      1. response.getOutputStream()获取字节输出流
  5. 使用IO流的框架进行边读边写

路径问题

一、完整url地址

url的组成部分:
  1. 协议 http://
  2. 服务器主机地址 localhost
  3. 服务器的端口号 :8080
  4. 项目的虚拟路径(部署路径) responseDemo
  5. 具体的项目上资源路径 /pages/hello.html 或者 /demo02 Servlet的映射路径
什么时候会使用完整的url
  1. 浏览器地址栏直接访问
  2. 一个项目中,访问另一个项目中的资源

二、相对路径

相对路径的概念

不以"/“开头的路径写法,它是以目标路径相对当前文件的路径,其中”…"表示上一级目录

它是以目标资源的url,相对当前资源的url

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
    <h1>hello world....</h1>
    <!--
        目标资源的url: http://localhost:8080/responseDemo/demo05
        当前资源的url: http://localhost:8080/responseDemo/pages/demo.html

        相对路径的优劣:
            1. 优势: 无论部署的项目名怎么改变,我的路径都不需要改变
            2. 劣势: 如果当前资源的位置发生改变,那么相对路径就必定要发生改变
    -->
    <a href="../demo05">访问ServletDemo05</a>
</body>
</html>

三、绝对路径

绝对路径的概念

绝对路径就是以"/"开头的路径写法,它有如下两种情况

  1. 请求转发的绝对路径写法 “/资源的路径”,不需要写项目路径,例如"/hello.html"
  2. 不是请求转发的绝对路径写法"/项目部署路径/资源路径" 例如 “/responseDemo/hello.html”

案例-完成文件下载

1.需求分析

  • 创建文件下载的列表的页面,点击列表中的某些链接,下载文件.

在这里插入图片描述

2.文件下载分析

2.1什么是文件下载

​ 将服务器上已经存在的文件,输出到客户端浏览器.

​ 说白了就是把服务器端的文件拷贝一份到客户端, 文件的拷贝—> 流(输入流和输出流)的拷贝

2.2文件下载的方式
  • 第一种:超链接方式(不推荐)

    链接的方式:直接将服务器上的文件的路径写到href属性中.如果浏览器不支持该格式文件,那么就会提示进行下载, 如果 浏览器支持这个格式(eg: png, jpg…)的文件,那么直接打开,不再下载了

  • 第二种:手动编码方式(推荐)

    手动编写代码实现下载.无论浏览器是否识别该格式的文件,都会下载.

3.思路分析

3.1超链接方式
  1. 准备下载的资源(文件)
  2. 编写一个下载页面
  3. 在这个页面上定义超链接,指定href
3.2编码方式
3.2.1手动编码方式要求

​ 设置两个头和一个流

​ 设置的两个头:

		Content-Dispostion: 服务器告诉浏览器去下载

		Content-Type: 告诉浏览器文件类型.(MIME的类型)  

​ 设置一个流:

		 获得要下载的文件的输入流.
3.2.2思路

在这里插入图片描述

4.代码实现

   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        //1.获得文件名fileName
        String fileName = request.getParameter("fileName");
        System.out.println("fileName="+fileName); //eg: a.jpg

        //2.设置两头一流
        //2.1 一流, 根据文件名获得文件的输入流
        InputStream is = getServletContext().getResourceAsStream("download/" + fileName);

        //2.2 一头, 告诉浏览器文件的MIME类型(可以不写)
        String mimeType = getServletContext().getMimeType(fileName);
        response.setHeader("Content-Type",mimeType);
       
        //2.3 一头, 告诉浏览器去下载
        response.setHeader("Content-Disposition","attachment;filename="+fileName);


        //3.通过response获得输出流(字节流)
        OutputStream os = response.getOutputStream();

        //4.流的操作
        byte[] b = new byte[1024];
        int len  = 0;
        while ( (len=is.read(b))!=-1 ){
            os.write(b,0,len);
        }
        is.close();
        os.close();

    }

5.细节处理

  • 告诉浏览器设置的响应头里面不支持中文的, 抓包来看:
    在这里插入图片描述

  • 解决方案: 手动进行编码再设置进去就ok了

中文文件在不同的浏览器中编码方式不同:火狐是Base64编码, 其它浏览器(谷歌)是URL的utf-8编码

if(agent.contains("Firefox")){
			// 火狐浏览器
			filename = base64EncodeFileName(filename);
		}else{
			// IE,其他浏览器
			filename = URLEncoder.encode(filename, "UTF-8");
		}

public static String base64EncodeFileName(String fileName) {
		BASE64Encoder base64Encoder = new BASE64Encoder();
		try {
			return "=?UTF-8?B?"
					+ new String(base64Encoder.encode(fileName
							.getBytes("UTF-8"))) + "?=";
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

第三章-综合案例

案例-注册

1. 需求

在这里插入图片描述

2. 路径

  1. 三层结构的讲解
  2. 完成注册功能

3. 代码实现

3.1 三层架构
  • 软件中分层:按照不同功能分为不同层,通常分为三层:表现层(web层),业务层,持久(数据库)层。

在这里插入图片描述

  • 不同层次包名的命名
分层包名(公司域名倒写)
表现层(web层)com.itheima.web
业务层(service层)com.itheima.service
持久层(数据库访问层)com.itheima.dao
JavaBeancom.itheima.bean
工具类com.itheima.utils
  • 分层的意义:
    1. 解耦:降低层与层之间的耦合性。
    2. 可维护性:提高软件的可维护性,对现有的功能进行修改和更新时不会影响原有的功能。
    3. 可扩展性:提升软件的可扩展性,添加新的功能的时候不会影响到现有的功能。
    4. 可重用性:不同层之间进行功能调用时,相同的功能可以重复使用。
  • 程序设计的宗旨:
    • 高内聚低耦合
    • 可扩展性强
    • 可维护性强
    • 可重用性强
3.2 完成注册案例
3.2.1 注册案例思路

在这里插入图片描述

3.2.2准备工作
  • 数据库
create database day25;
use day25;
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(40) DEFAULT NULL,
  `password` varchar(40) DEFAULT NULL,
  `address` varchar(40) DEFAULT NULL,
  `nickname` varchar(40) DEFAULT NULL,
  `gender` varchar(10) DEFAULT NULL,
  `email` varchar(20) DEFAULT NULL,
  `status` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8
  • JavaBean
public class User implements Serializable{
    private Integer id;
    private String username;
    private String password;
    private String address;
    private String nickname;
    private String gender;
    private String email;
    private String status;//1 表示已激活  0表示未激活
	//...
}
  • 导入jar
    • mysql驱动
    • druid
    • dbutils
    • beanutils
  • 工具类和配置文件
    • DruidUtil
    • druid.properties
3.2.3 注册案例实现

注册页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
</head>
<body>
    <form action="/userDemo/register" method="post">
        用户名<input type="text" name="username"><br>
        密码<input type="text" name="password"><br>
        昵称<input type="text" name="nickname"><br>
        地址<input type="text" name="address"><br>
        邮箱<input type="text" name="email"><br>
        性别<input type="radio" name="gender" value="male"><input type="radio" name="gender" value="female"><br>
        <input type="submit" value="注册">
    </form>
</body>
</html>

RegisterServlet的代码

/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  16:15
 */
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //在最前面解决乱码问题:请求参数的中文乱码,响应的中文乱码
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

        //1. 获取所有的请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();

        //2. 使用BeanUtils 将parameterMap中的数据,存储到User对象中
        User user = new User();

        //设置默认的status为"0"
        user.setStatus("0");

        try {
            BeanUtils.populate(user,parameterMap);

            //3. 使用DBUtils将用户信息存储到数据库
            //这里需要mysql驱动、druid、dbutils的jar包
            QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
            String sql = "insert into user values (null,?,?,?,?,?,?,?)";

            queryRunner.update(sql,user.getUsername(),user.getPassword(),user.getAddress(),
                              user.getNickname(),user.getGender(),user.getEmail(),user.getStatus());

            //如果存储的时候没有出现问题,则说明注册成功,使用重定向跳转到登录页面
            response.sendRedirect("/userDemo/login.html");
        } catch (Exception e) {
            e.printStackTrace();

            //如果注册失败,则向浏览器响应一句"注册失败"
            response.getWriter().write("注册失败");
        }
    }
}

4. 小结

  1. 注册本质: 向数据库插入一条记录
  2. 思路(在RegisterServlet)
    • 获得用户提交的数据, 使用BeanUtils封装成User对象
    • 补全User对象(状态)
    • 使用DBUtils向数据库里面插入一条记录
    • 响应

案例-登录

1.需求

在这里插入图片描述

  • 点击登录按钮, 进行登录.
  • 登录成功,显示login Success
  • 登录失败,显示login failed

2.思路

在这里插入图片描述

3.代码实现

3,1准备工作
  • 页面的准备 login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
    <form action="/userDemo/login" method="post">
        用户名<input type="text" name="username"><br>
        密码<input type="text" name="password"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>
3.2代码实现
/**
 * 包名:${PACKAGE_NAME}
 *
 * @author Leevi
 * 日期2020-07-12  16:44
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        try {
            //1. 解决乱码
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");

            //2. 获取请求参数username和password
            String username = request.getParameter("username");
            String password = request.getParameter("password");

            //3. 连接数据库校验用户名和密码,也就是执行查询的SQL语句
            QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
            String sql = "select * from user where username=? and password=?";
            //执行查询,查询一条数据,封装到User中
            User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
            //判断是否登录成功
            if (user != null) {
                //登录成功
                //跳转到成功页面success.html
                response.sendRedirect("/userDemo/success.html");
            }else {
                //登陆失败,直接向浏览器输出"登陆失败"
                response.getWriter().write("登陆失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            //登陆失败,直接向浏览器输出"登陆失败"
            response.getWriter().write("登陆失败");
        }
    }
}

4.小结

  1. 本质: 就是根据用户名和密码查询数据库
  2. 思路(LoginServlet)
    • 获得用户输入用户名和密码
    • 使用DBUtils根据用户名和密码查询数据库 封装成User对象
    • 判断是否登录成功(判断User是否为null)
    • 响应

sponse response) throws ServletException, IOException {
try {
//1. 解决乱码
request.setCharacterEncoding(“UTF-8”);
response.setContentType(“text/html;charset=UTF-8”);

        //2. 获取请求参数username和password
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //3. 连接数据库校验用户名和密码,也就是执行查询的SQL语句
        QueryRunner queryRunner = new QueryRunner(DruidUtil.getDataSource());
        String sql = "select * from user where username=? and password=?";
        //执行查询,查询一条数据,封装到User中
        User user = queryRunner.query(sql, new BeanHandler<>(User.class), username, password);
        //判断是否登录成功
        if (user != null) {
            //登录成功
            //跳转到成功页面success.html
            response.sendRedirect("/userDemo/success.html");
        }else {
            //登陆失败,直接向浏览器输出"登陆失败"
            response.getWriter().write("登陆失败");
        }
    } catch (Exception e) {
        e.printStackTrace();
        //登陆失败,直接向浏览器输出"登陆失败"
        response.getWriter().write("登陆失败");
    }
}

}


### 4.小结

1. 本质: 就是根据用户名和密码查询数据库
2. 思路(LoginServlet)
   + 获得用户输入用户名和密码
   + 使用DBUtils根据用户名和密码查询数据库 封装成User对象
   + 判断是否登录成功(判断User是否为null)
   + 响应

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值