复习3:Request和Response

1.Servlet的相关知识

  1. 首先是要清楚Servlet的一个体系结构,原先我们是通过实现Servlet接口并重写其中的抽象方法来实现类的创建的。就像下面这样:
package cn.itcast.web.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo1")
public class ServletDemo1 implements Servlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

    @Override
    public ServletConfig getServletConfig() {
        return null;
    }
    //提供服务的方法
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet");
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象,将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可。

package cn.itcast.web.servlet;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
@WebServlet("/demo1")
public class ServletDemo1 extends GenericServlet {

    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        System.out.println("Hello Servlet");
    }
}

HttpServlet:对http协议的一种封装,简化操作
1. 定义类继承HttpServlet
2. 复写doGet/doPost方法

package cn.itcast.web.servlet;

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;

@WebServlet("/demo2")
public class ServletDemo2 extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //注意这里一定要把继承自父类的方法那个super啥的给删掉哈
        System.out.println("doGet....");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doPost......");
    }
}

2.Request对象

  1. 首先要对请求消息的数据格式有一定的了解:
    复习3:Request和Response_第1张图片
POST /login.html	HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Referer: http://localhost/login.html
Connection: keep-alive
Upgrade-Insecure-Requests: 1

username=zhangsan
  1. 接着就开始介绍获取请求消息每一部分的各种方法:
    复习3:Request和Response_第2张图片
    在这里插入图片描述
    复习3:Request和Response_第3张图片
    其中获取请求体数据的方法不经常用,而是采用其他POST和GET的通用方法来获取请求数据,如下:
    复习3:Request和Response_第4张图片
    需要注意的是:
    1.这些方法的返回值
    2.请求头中有两个属性比较重要:
    1)user-agent,来获取浏览器的种类
    2)referer,进行防盗链和流量统计
    以下就是两个属性的典型用法:
package cn.itcast.web.request;

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.util.Enumeration;

@WebServlet("/requestDemo3")
public class RequestDemo3 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String agent = req.getHeader("user-agent");
        if (agent.contains("Chrome")) {
            System.out.println("谷歌来了...");
        } else if (agent.contains("Firefox")) {
            System.out.println("火狐来了...");
        }
    }

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

    }
}
package cn.itcast.web.request;

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;

@WebServlet("/requestDemo4")
public class RequestDemo4 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String referer = req.getHeader("referer");
        System.out.println(referer);
        //防盗链
        if(referer != null){
            if(referer.contains("/day14")){
                System.out.println("正常访问");
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("播放电影....");
            }else{
                System.out.println("盗链");
                resp.setContentType("text/html;charset=utf-8");
                resp.getWriter().write("想看电影吗?来优酷吧...");
            }
        }
    }

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

    }
}

3)枚举Enumeration采用hasMoreElements()和nextElement()进行其中元素的访问

  1. 请求转发和共享数据
    复习3:Request和Response_第5张图片
  2. 用户登录的案例

1)首先还是利用sql语句创建一个数据库和用户表

CREATE DATABASE day14;
CREATE TABLE USER(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(32) UNIQUE NOT NULL,
	PASSWORD VARCHAR(32) NOT NULL
);
Insert into user values (null, "张三","123");

2)用HTML语句写一个简单的表单


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>

<form action="/request/loginServlet" method="post">
    用户名:<input type="text" name="username"><br/>
    密  码:<input type="password" name="password"><br/>
    <input type="submit" value="登录">
form>
body>
html>

3)创建对应的用户对象,写出set()、get()方法,重写toString()方法

package domain;

public class User {
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

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

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

4)再次写出工具类用于创建连接对象

package cn.itcast.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * JDBC工具类 使用Durid连接池
 */
public class JDBCUtils {

    private static DataSource ds ;

    static {

        try {
            //1.加载配置文件
            Properties pro = new Properties();
            //使用ClassLoader加载配置文件,获取字节输入流
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            pro.load(is);

            //2.初始化连接池对象
            ds = DruidDataSourceFactory.createDataSource(pro);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接池对象
     */
    public static DataSource getDataSource(){
        return ds;
    }


    /**
     * 获取连接Connection对象
     */
    public static Connection getConnection() throws SQLException {
        return  ds.getConnection();
    }
}

5)我们接着就是先把数据库JDBC的这一部分写好,也就是一个密码校验的函数,即一条查找语句,查找是否有对应的用户名和密码同时出现在表格的一行中。

package dao;

import domain.User;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import util.JDBCUtils;

public class UserDao {
    private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
    public User login(User loginUser){
        //这里是为了不让最后查询不到结果而报异常,所以就用try语句将其包裹一下,包裹快捷键:ctrl+alt+t
        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) {
            return null;
        }
    }
}

这里注意如果没有查找到就会抛出异常,这个时候我们就需要用try语句将其包裹一下,然后再到catch中返回一个null。
5)接着就是从请求数据中读取响应的请求参数了,并使用我们上一步定义的查询函数进行查询

package servlet;

import dao.UserDao;
import domain.User;

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;

@WebServlet("/loginServlet")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        User loginuser = new User();
        loginuser.setUsername(username);
        loginuser.setPassword(password);
        UserDao dao = new UserDao();
        User user = dao.login(loginuser);
        if(user == null){
            req.getRequestDispatcher("/failServlet").forward(req,resp);
        }else{
            req.setAttribute("user",user);
            req.getRequestDispatcher("/sucessServlet").forward(req,resp);
        }
    }

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

6)设置好处理的函数,可以直接向页面输出登录是否成功,如果成功,还需要将用户名一起输出。

package servlet;

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;

@WebServlet("/failServlet")
public class FailServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("登录失败");
    }

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

package servlet;

import domain.User;

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;
@WebServlet("/sucessServlet")
public class SucessServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        User user = (User)req.getAttribute("user");
        if(user != null){
            resp.setContentType("text/html;charset=utf-8");
            resp.getWriter().write("登陆成功"+user.getUsername());
        }
    }

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

7)最后有一点需要强调的是文件的一个结构
复习3:Request和Response_第6张图片
注意这里是WEB-INF而不是WEB_INF,然后这个目录下面只有一个lib文件夹,前端页面的html文件是在web文件夹下的。

3.Response对象

  1. 还是需要了解服务器向客户端发送的消息的格式:
    复习3:Request和Response_第7张图片
    以下是一个例子:
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 101
Date: Wed, 06 Jun 2018 07:08:42 GMT

<html>
  <head>
    <title>$Title$title>
  head>
  <body>
  hello , response
  body>
html>
  1. 接下来便是设定这些信息了
    复习3:Request和Response_第8张图片
    这里响应头中的location属性就是为了重定向设计的,我们的重定向实现其实有两种写法:
resp.setHeader("location", "/day15/responseDemo2");
resp.sendRedirect(contextPath+"/responseDemo2");
  1. 这里又是一个面试的考点,就是考查响应对象的重定向和请求对象中的转发的异同。
    复习3:Request和Response_第9张图片
    还涉及一个知识点就是路径的写法,为什么有时候要加虚拟目录,有时候不加虚拟目录:
    复习3:Request和Response_第10张图片
  2. 这里有一个解决浏览器显示中文出现的问题,具体解释看注释:
package cn.itcast.web.response;

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;

@WebServlet("/responseDemo3")
public class ResponseDemo3 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取流对象之前,设置流的默认编码:ISO-8859-1 设置为:GBK
        //resp.setCharacterEncoding("GBK");
        //这个时候只是一个巧合,只是我们知道这个浏览器是采用GBK来进行解码的,如果换一个浏览器用utf-8来解码就不行;额
        //所以告诉浏览器,服务器发送的消息体数据的编码。建议浏览器使用该编码解码既可以设置流的编码也可以设置浏览器的编码
        //而且仅仅这一行就够了,
        //resp.setHeader("content-type","text/html;charset=utf-8");
        //因为这一行相当于是必写的,所以还有一种简单的形式
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter pw = resp.getWriter();
        pw.write("

hello response

"
); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } }
  1. ServletContext对象
    复习3:Request和Response_第11张图片
  2. 文件下载案例
package cn.itcast.web.download;

import cn.itcast.web.util.DownLoadUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;

@WebServlet("/downloadServlet")
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String filename = req.getParameter("filename");
        ServletContext context = this.getServletContext();
        String realPath = context.getRealPath("/img/" + filename);
        FileInputStream fis = new FileInputStream(realPath);
        //设置响应头
        String mimeType = context.getMimeType(filename);
        resp.setHeader("content-type",mimeType);
        String agent = req.getHeader("user-agent");
        filename = DownLoadUtils.getFileName(agent,filename);
        resp.setHeader("content-disposition","attachment;filename="+filename);
        ServletOutputStream sos = resp.getOutputStream();
        byte[] buff = new byte[1024*8];
        int len = 0;
        while((len = fis.read(buff))!=-1){
            sos.write(buff,0,len);
        }
    }

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

中文文件问题
* 解决思路:
1. 获取客户端使用的浏览器版本信息
2. 根据不同的版本信息,设置filename的编码方式不同

所以采用了一个工具类DownLoadUtils:

package cn.itcast.web.util;

//import sun.misc.BASE64Encoder;
import org.apache.commons.codec.binary.Base64;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;


public class DownLoadUtils {

    public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
        if (agent.contains("MSIE")) {
            // IE浏览器
            filename = URLEncoder.encode(filename, "utf-8");
            filename = filename.replace("+", " ");
        } else if (agent.contains("Firefox")) {
            // 火狐浏览器
            filename = "=?utf-8?B?" + Base64.encodeBase64String(filename.getBytes("utf-8")) + "?=";
        } else {
            // 其它浏览器
            filename = URLEncoder.encode(filename, "utf-8");
        }
        return filename;
    }
}

你可能感兴趣的:(JAVA学习)