Servlet进阶

﹥>﹥吖頭↗ 提交于 2019-12-05 17:48:54

第一节 页面跳转

作为后台开发人员, 我们大多时候都在接收处理用户请求, 给予用户响应, 为了方便操作, 服务器需要将请求和响应封装成了request和response, Java Web服务端控制页面跳转主要有两种: 重定向和转发

1.1 重定向

重定向就是通过各种方法将网络请求重新定个方向转到其它位置

实现原理

1. 客户浏览器发送http请求, web服务器接受后发送302状态码响应以及对应新的location给客户浏览器
2. 客户浏览器发现是302响应, 则自动再发送一个新的http请求, 请求url是新的location地址, 服务器根据此请求寻找资源并发送给客户
3. 在这里location可以重定向到任意URL, 既然是浏览器重新发出了请求, 则就没有什么request传递的概念了, 在客户浏览器路径栏显示的是其重定向的路径, 客户可以观察到地址的变化的

特点

1. 重定向是客户端行为。
2. 重定向是浏览器做了至少两次的访问请求。
3. 重定向浏览器地址改变。
4. 重定向两次跳转之间传输的信息会丢失(request范围)。
5. 重定向可以指向任何的资源, 包括当前应用程序中的其他资源, 同一个站点上的其他应用程序中的资源, 其他站点的资源
6. 注意:传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头, 它是相对于整个WEB站点的根目录

1.2 实现重定向

servlet代码

@WebServlet(name = "Servlet1", value = "/servlet1")
public class Servlet1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servlet1");
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        // 返回"/web", /+项目名称
        System.out.println(request.getContextPath());
        response.sendRedirect(request.getContextPath() + "/servlet2");
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

1.3 请求转发

Servlet除了支持重定向之外还支持请求转发

转发的原理

1. 客户浏览器发送http请求, web服务器接受此请求, 调用内部的一个方法在容器内部完成请求处理和转发动作, 将目标资源发送给客户
2. 在这里, 转发的路径必须是同一个web容器下的url, 其不能转向到其他的web路径上去, 中间传递的是自己的容器内的request, 在客户浏览器路径栏显示的仍然是其第一次访问的路径, 也就是说客户是感觉不到服务器做了转发的

特点

1. 转发是服务器行为
2. 转发是浏览器只做了一次访问请求
3. 转发浏览器地址不变
4. 转发两次跳转之间传输的信息不会丢失, 所以可以通过request进行数据的传递
5. 转发只能将请求转发给同一个WEB应用中的组件
6. 注意: 如果创建RequestDispatcher 对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录

1.4 实现请求转发

@WebServlet(name = "Servlet1", value = "/servlet1")
public class Servlet1 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servlet1");
        request.setCharacterEncoding("utf-8");
        String username = request.getParameter("username");
        request.getRequestDispatcher("/servlet2").forward(request, response);
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

1.5 网络路径问题

路径分类

绝对路径

用在不同网站之间的跳转, 比如:http://www.baidu.com/aaa/1.jpg

相对路径

用在同一个网站中, 例如: aaa/1.jpg, 仅限静态资源, 如果页面比较多, 并且使用框架,会出现混乱

根路径
根指定就是主机名(服务器)
  1. /web/loginservlet 如果在浏览器中使用 / 表示 http://localhost:8080/
  2. /listservlet 如果是在服务器中使用 / 表示 /web

第二节 response对象

在Servlet中可以使用的内置对象主要有: request、response、application、session、PrintWriter

2.1 ServletResponse简介

定义辅助 servlet 将响应发送到客户端的对象, servlet 容器创建 ServletResponse 对象, 并将它作为参数传递给 servlet 的 service 方法, 要发送 MIME正文响应中的二进制数据, 请使用 getOutputStream 返回的 ServletOutputStream; 要发送字符数据, 请使用 getWriter 返回的 PrintWriter 对象

2.2 HttpServletResponse介绍

扩展 ServletResponse 接口以提供特定于 HTTP 的发送响应功能, 例如, 该接口拥有访问 HTTP 头和 cookie 的方法, 客户端向服务器发起的都是HTTP协议操作, 所以我们大部分使用HttpServletResponse对象作为直接操作对象

2.3 HttpServletResponse 常用API介绍

方法名称 作用
setStatus(int code) 设置响应状态码:200 成功 302 临时重定向 304 处理缓存 404 Not Found没有找到资源,500 服务器错误
setHeader(name,value) 设置响应信息头
setCharacterEncoding(String); 设置编码格式
setContentType(String) 设置返回数据mimetype
getWriter() 获取字符输出流
getOutputStream() 获取字节输出流

2.4 设置返回字符编码格式

方案1

response.setCharacterEncoding("utf-8");
设置tomcat编码格式
<html>
	<head>
		<meta charset="utf-8">
  		<title>xxx</title>
	</head>
	<body>编写返回的文本内容</body>
</html>
设置浏览器解析文本内容格式

可以解决返回字符串乱码问题, 但是需要将返回的字符串封装到html代码中, 操作繁琐

方案2

response.setHeader("Content-type","text/html;charset=UTF-8")

方案按相对简单,通过设置响应头告知浏览器解析字符串的编码格式

方案3(推荐)

response.setContentType("text/html;charset=UTF-8")

利用setContentType这种综合性的写法解决问题, 此方法也是开发中常用的方法,方便

2.5 response练习

用户下载服务器图片

@WebServlet(name = "Servlet3", value = "/servlet3")
public class Servlet3 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("servlet3");
        // 设置响应头: content-disposition
        // 下载用的 attachment下载: filename下载文件的名字
        response.setHeader("content-disposition",
                "attachment;filename="+ URLEncoder.encode("copy.jpg", "utf-8"));
        // getServletContext() 获取servlet上下文 getRealPath 获取项目运行时的路径
        // 获取绝对路径
        String path = request.getServletContext().getRealPath("/copy.jpg");
        System.out.println(path);
        // 文件输入流
        FileInputStream fis = new FileInputStream(path);
        byte[] buf = new byte[1024];
        int len = 0;
        // 字节输出流
        ServletOutputStream os = response.getOutputStream();
        while ((len=fis.read(buf)) != -1){
            os.write(buf, 0, len);
        }
        fis.close();
        os.close();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

页面中添加验证码

  1. 验证码作用:防止机器攻击。
  2. 项目中添加第三方jar包validatecode.jar
  3. 创建返回验证码的servlet!
public class Servlet4 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 验证码的宽度、高度、生成验证码的个数、有几根线
        ValidateCode validateCode = new ValidateCode(100, 30, 4, 20);
        // 获取生成的验证码字符串
        String code = validateCode.getCode();
        System.out.println(code);
        // 响应客户端, 输出验证码的图片
        validateCode.write(response.getOutputStream());
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
页面中使用当前servlet
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/web/servlet5" method="post">
        用户名:<input type="text" name="name"><br>
        年龄:<input type="text" name="age"><br>
        验证码:<input type="text" name="vcode"><img id="img1" src="servlet4" onclick="changeImg()">
                <a href="" onclick="return changeImg()">看不清</a><br>
        <input type="submit">
        <script type="text/javascript">
            function changeImg() {
               var element = document.getElementById("#img1");
               element.src = "servlet4?n="+Math.random();
               return false;
            }
        </script>
    </form>
</body>
</html>

第三节 request对象

3.1 ServletRequest介绍

定义将客户端请求信息提供给某个 servlet 的对象, servlet 容器创建ServletRequest 对象, 并将该对象作为参数传递给该 servlet 的service方法

3.2 HttpServletRequest介绍

  • HttpServletRequest对象代表客户端的请求, 当客户端通过HTTP协议访问服务器时, HTTP请求头中的所有信息都封装在这个对象中, 开发人员通过这个对象的方法, 可以获得客户这些信息。
  • 同响应相同, 客户端请求协议都是基于HTTP所以我们选用HttpServletRequest来操作用户发送过来的请求的数据

3.3 HttpServletRequest常用API

  • URL: Uniform Resource Location (统一资源定位符) 网址
  • URI: Uniform Resource Identifier (统一资源标识符) URI包含URL
//获取请求路径相关参数
getRequestURL方法返回客户端发出请求时的完整URL。
getRequestURI方法返回请求行中的资源名部分。
getQueryString 方法返回请求行中的参数部分。
getRemoteAddr方法返回发出请求的客户机的IP地址
getRemoteHost方法返回发出请求的客户机的完整主机名
getRemotePort方法返回客户机所使用的网络端口号
getLocalAddr方法返回WEB服务器的IP地址。
getLocalName方法返回WEB服务器的主机名
getMethod得到客户机请求方式
//获取请求头信息
getHead(name)方法
getHeaders(String name)方法
getHeaderNames方法
//获取请求正文参数
getParameter(name)方法
getParameterValues(String name)方法
getParameterNames方法
getParameterMap方法  //做框架用,非常实用
getInputStream方法 获取输入流

3.4 获取请求数据练习

@WebServlet(name = "Servlet8", value = "/servlet8")
public class Servlet8 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.测试获取请求行数据的方法和请求头的方法
        //1.获取请求行的方法
        //获取请求方式
        String method = request.getMethod();
        //获取请求的url 
        String url = request.getRequestURL()+"";
        //获取uri 
        String uri = request.getRequestURI();
        //获取请求的参数  get
        String query = request.getQueryString();
        //获取请求人的ip
        String ip = request.getRemoteAddr();
        //获取请求的主机名
        String host = request.getRemoteHost();
        System.out.println(method+" url:"+url+" uri:"+
                uri+" query:"+query+" ip:"+ip+" host:"+host);
        //获取请求信息
        //全部输出  
        //post fix
        String header = request.getHeader("user-agent");
        if(header.contains("firefox")) {
            System.out.println("firefox");

        }
        //获取所有请求的names
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = (String) headerNames.nextElement();
            //根据name获取keys
            Enumeration<String> headers = request.getHeaders(name);
            while (headers.hasMoreElements()) {
                String key = (String) headers.nextElement();
                System.out.println(name+"--->"+key);
            }
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}

3.5 封装请求参数

将数据封装到实体类上

创建一个对应的实体类, 实体类要变量命名和变量类型都有相应的要求, 要求变量名跟提交参数的key相同, 变量跟参数类型相同

public class User {
    private String name;
    private String age;

    public User() {
    }

    public User(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

使用Apache BeanUtils进行快速映射

  1. 导入beanutils对应jar包、logging日志、commons-collections-3.2.1.jar
  2. 映射
@WebServlet(name = "Servlet5", value = "/servlet5")
public class Servlet5 extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        User user = new User();
        try {
            // 将Map数据封装到指定Javabean中, 一般用于将表单的所有数据封装到javabean
            BeanUtils.populate(user, request.getParameterMap());
            System.out.println(user.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!