http的request和response

HTTP

超文本传输协议:定义客户端和服务器之间传输数据的格式

特点:

  • 基于TCP/IP的高级协议
  • 默认端口号:80
  • 基于请求/响应模型:一次请求对应一次响应
  • 无状态的:每次请求之间相互独立

历史版本:

  • 1.0:每次请求响应都会建立新的连接(一个网页需要多个请求)
  • 1.1:复用连接

传输过程:

  1. tomcat根据请求url中的资源路径,根据配置文件找到Servlet实现类,并创建对象;
  2. tomcat创建request和response对象,requeset对象中封装请求消息;
  3. tomcat调用service方法
  4. 程序员在service中,根据请求消息,设置相应数据
  5. tomcat将response返给浏览器

Request

请求消息数据格式:

  1. 请求行 请求方式 请求url 请求协议/版本

    如:GET /day04/demo1?name=zhangsan HTTP/1.1

  2. 请求头 请求头名称:请求头值 (多个请求头)

    • User-Agent:浏览器版本等信息
    • Referer:请求来自哪个网站
  3. 请求空行:就是一个空行

  4. 请求体

    • GET没有,POST有

request类

ServletRequest 接口

HttpServletrequest 接口,继承上面的接口

org.apache.catalina.connector.RequestFacade 类,由Tomcat实现,继承上面接口

所以,Tomcat实现request类

request对象

常用方法

  1. 获取请求行数据(几个常用的)
    • 获取虚拟目录:String getContextPath()
    • 获取URI:String getRequestURI()/day04/demo
    • 获取URL:StringBuffer getRequestURL()http://localhost/day04/demo
  2. 获取请求头数据
    • String getHeader(String name) 根据请求头名称获得值
  3. 获取请求体数据 (POST请求方式)
    • 获取流对象:字符流 getReader() 字节流getInputStream()
    • 从流对象中拿数据

其他方法

  • 获取请求参数通用方法 (GET和POST都可以)

    • String getParameter(String name) 更根据参数名称获取参数值
    • String[] getParameterValues(String name) 更根据参数名称获取参数组
    • getParameterNames() 获取所有请求的参数名称
    • Map<String String[]> getParameterNames() 获取所有请求的参数map集合
    • POST会遇到中文乱码,需要先设置req.setCharacterEncoding("utf-8")
  • 请求转发:服务器内部的资源跳转方式(如Demo1转到Demo2)req.getRequestDispatcher("/demo2").forward(req, resp);

    特点:浏览器地址栏没有发生变化;只能转发到当前服务器内部资源。

  • 共享数据

    • 域对象:一个有作用范围的对象,可以在范围内共享数据
    • request域:代表一次请求的范围,一般用于请求转发的多个资源中共享数据
      1. setAttribute(String name, Object obj) 存储数据
      2. Object getAttrbute(String name) 通过键获取值
      3. removeAttribute(String name) 通过键移除键值对
  • 获取ServletContext

    • ServletContext getServletContext() 后面再讲

案例

用户登录的业务逻辑:

  1. 创建项目,导入login.html
  2. 创建数据库中的user表
  3. 创建User类
  4. 创建JDBCUtils工具类(获取连接池,获取链接对象)
  5. 创建UserDao类,实现login方法(使用JDBCTemplate执行sql查询)
  6. 创建loginServlet类:
    • 获取请求参数 (username, password)
    • 封装成User对象
    • 调用UserDao的login方法 (传入User对象,执行sql语句,判断)
    • 判断是否登录成功

BeanUtils工具类:简化 请求参数 的封装

  1. 导入jar包commons-beanutils-1.8.0.jar
  2. User类必须符合JavaBean标准(JavaBean是定义一个Java类的标准的要求,可百度搜索)

BeanUtils代码:(Servlet中)

// 设置请求数据编码
req.setCharacterEncoding("UTF-8");
// 获取提交数据
Map<String, String[]> map = req.getParameterMap();
// 创建对象
User loginUser = new User();
// 封装对象
BeanUtils.populate(loginUser, map);  // try-catch捕获
// 登录判断
UserDao dao = new UserDao();
User user = dao.login(loginUser);
if (user == null) {
	System.out.println("登录失败");
} else {
	System.out.println("登录成功");
}

案例代码

文件目录结构:

--项目/模块
	--src/包
		druid-properties // 连接池配置文件
		domain/User
		dao/UserDao
		util/JDBCUtils
		servlet/ServletDemo
	--web
		--WEB-INF
			lib // jar包,需要右键add as libaray
		xxx.html
		xx.jsp

login.html

<form action="./demo" method="post">
    username: <input type="text" name="username"> <br>
    password: <input type="password" name="password"> <br>
    <input type="submit" value="submit">
</form>

User略 (JavaBean标准类)

JDBCUtils略 (参考JDBC中的Druid连接池,一模一样)

UserDao类:

public class UserDao {
    // 声明JDBCTemplate对象共用
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

    public User login(User loginUser) {
        try {
            String sql = "select * from user where username=? and password=?";
            User user = template.queryForObject(sql,
                    new BeanPropertyRowMapper<User>(User.class),
                    loginUser.getUsername(), loginUser.getPassword());
            return user;
        } catch (DataAccessException e) {
            e.printStackTrace();
            return null;
        }
    }
}

Servlet类,参考上面BeanUtils

Response

响应消息格式:

  1. 响应行:协议/版本 响应状态码 状态码描述HTTP/1.1 200 OK
    • 响应状态码:都是3位数,分为5类
      • 1xx 服务器收到消息,但没有接受完成
      • 2xx 成功200
      • 3xx 重定向 (302重定向 304访问缓存)
      • 4xx 客户端错误 (404请求路径错误 405请求方法没有对应的doXx方法)
      • 5xx 服务器错误 (500服务内异常)
  2. 响应头 头名称:值
    • Content-type:响应数据格式(html),以及编码格式
    • Content-disposition:以什么格式打开响应数据(当前页面内打开、附件下载等)
  3. 响应空行:空行
  4. 响应体:HTML代码/图片的编码

response对象

常用方法

  1. 设置响应行:setStatus(int sc)
  2. 设置响应头:setHeader(String name, String value)
  3. 设置响应体:
    • 获取输出流:字符输出流getWriter()、字节输出流getOutputStream()
    • 使用输出流,将数据输出到客户端

其他方法

  1. 重定向:resp.sendRedirect("/day04/ServletDemo2")

    • 重定向特点:地址栏发生变化,属于两次请求,可以访问其他站点资源,不能共享数据
    • 转发特点:地址栏不变,是一次请求,只能访问当前站点资源,能共享数据
    • 可以获取虚拟目录:String req.getContextPath()
  2. 告诉浏览器编码方式 resp.setContentType("text/html;charset=utf-8");

  3. 字符流

    resp.setContentType("text/html;charset=utf-8");
    PrintWriter pw = resp.getWriter();
    pw.write("你好 hello");
    
  4. 字节流

    resp.setContentType("text/html;charset=utf-8");
    ServletOutputStream os = resp.getOutputStream();
    os.write("你好".getBytes("utf-8"));
    

ServletContext

概念:代表整个web应用,可以和程序的服务器交互

获取ServletContext对象:

  1. req.getServletContext();
  2. this.getServletContext(); (建议使用)

功能:

  1. 获取MIME类型

    • MIME类型:互联网通信定义的一种文件数据类型

    • MIME格式:大类型/小类型, 如 text/html

    •   ServletContext context1 = req.getServletContext();
        String filename = "a.jpg";
        System.out.println(context1.getMimeType(filename)); // 输出image/jpeg
      
  2. 域对象:共享数据:所有用户,所有数据

    • setAttribute(String, Object);
    • getAttribute(String);
    • removeAttribute(String)
  3. 获取文件在服务器中的路径

    ServletContext c = this.getServletContext();
    String path = c.getRealPath("/b.txt");  // web目录下的资源路径
    String path2 = c.getContextPath("/WEB-INF/classes/a.txt"); // src目录下的资源路径
    

下载功能

现在浏览器比较高级,一些文件可以自动转到下载功能。

对于任何文件,如何实现下载功能(让浏览器下载):

  • 使用响应头设置资源的打开方式:content-disposition:attachment;filename=xxx(以附件形式打开)

实现:

  1. 超链接指向servlet (传递文件名);
  2. servlet获取文件名;加载文件进内存;指定response响应头;将文件写到response输出流中。

代码:

  1. html页面:

    • 图片放在web/img/687.png,必须有img文件夹
    • servlet是虚拟目录,demo是servlet资源路径
     <a href="/servlet/demo?filename=1.png">图片下载</a>
    
  2. servlet编程:

    // 获取参数
    String filename = req.getParameter("filename");
    // 找到资源路径
    ServletContext c = this.getServletContext();
    String realPath = c.getRealPath("/img/" + filename);
    // 设置响应头(文件类型)
    String mimeType = c.getMimeType(filename);
    resp.setHeader("content-type", mimeType);
    // 设置响应头(浏览器打开方式)
    resp.setHeader("content-disposition", "attachment;filename="+filename);
    // 字节流加载
    FileInputStream is = new FileInputStream(realPath);
    // 数据输出
    ServletOutputStream os = resp.getOutputStream();
    byte[] buff = new byte[2014 * 8];
    int len = 0;
    while ((len = is.read(buff)) != -1) {
        os.write(buff, 0, len);
    }
    is.close();
    

中文乱码

刚才下载的文件,如果是中文,不同浏览器显示不一样的编码。

解决思路:

  1. 获取客户端使用的浏览器版本信息
  2. 根据不同的版本,设置不同的编码方式

代码:

  1. 将DownLoadUtils.java文件(工具类)放在utils工具包
  2. servlet中编码
    String agent = req.getHeader("user-agent");
    filename = DownLoadUtils.getFileName(agent, filename);
原文地址:https://www.cnblogs.com/mingriyingying/p/13477284.html