http中的request的操作

首先,你要明白过滤bai器的原理。过滤器执du行完chain.dofilter(req,resp)后,放行到你所zhi在的servlet或jsp,执行完servlet或者daojsp后,或重新回到过滤器执zhuan行完剩余代码,要是你在剩余代码中又有请求发出,程序就会发生发出多次请求错误。总的来说,就是chain.dofilter(req,resp)下面的代码不能有请求,如果有,请加上return。
如果跳转写在方法里,记得让方法也一起跳转让
return层层跳转上去

request.getRequestDispatcher()之后一定要return
调用request的方法也request.
getRequestDispatcher(path).forward(),执行完,后面的代码居然还会执行!!!记得加return 啊亲
尽管HttpServletResponse.sendRedirect方法和RequestDispatcher.forward方法都可以让浏览器获得另外一个URL所指向的资源,但两者的内部运行机制有着很大的区别。下面是HttpServletResponse.sendRedirect方法实现的请求重定向与RequestDispatcher.forward方法实现的请求转发的总结比较:

(1)RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而 HttpServletResponse.sendRedirect 方法不仅可以重定向到当前应用程序中的其他资源,还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于整个WEB站点的根目录 ;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录 。

(2)调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;而调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。

(3)HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求,这个过程好比有个绰号叫“浏览器”的人写信找张三借钱,张三回信说没有钱,让“浏览器”去找李四借,并将李四现在的通信地址告诉给了“浏览器 ”。于是,“浏览器”又按张三提供通信地址给李四写信借钱,李四收到信后就把钱汇给了“浏览器”。可见,“浏览器”一共发出了两封信和收到了两次回复,“ 浏览器”也知道他借到的钱出自李四之手。RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。这个过程好比绰号叫“浏览器”的人写信找张三借钱,张三没有钱,于是张三找李四借了一些钱,甚至还可以加上自己的一些钱,然后再将这些钱汇给了“浏览器”。可见,“浏览器”只发出了一封信和收到了一次回复,他只知道从张三那里借到了钱,并不知道有一部分钱出自李四之手。

(4)RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程 ;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程 。对于同一个WEB应用程序的内部资源之间的跳转,特别是跳转之前要对请求进行一些前期预处理,并要使用HttpServletRequest.setAttribute方法传递预处理结果,那就应该使用 RequestDispatcher.forward方法。不同WEB应用程序之间的重定向,特别是要重定向到另外一个WEB站点上的资源的情况,都应该使用HttpServletResponse.sendRedirect方法。

(5)无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。

(6) 代码的执行:

无论是 request.getRequestDispatcher(path).forward(request, response)还是response.sendRedirect,程序都会在执行完该句的情况下继续向下执行,因此在必要的时候应该使用return终止该方法.

对于 request.getRequestDispatcher(path).forward(request, response),在执行完该方法的时候再进行对request的操作已经没有任何意义,如果在该方法之后再进行request.setAttribute(),该值将不会被放进当前请求的request中.

response.setRedirect:该方法执行之后,接下来的方法也会被执行.但是使用该方法的时候,会发送一个全新的request,将不再使用原先的request,因此不论在该方法执行之前,还是在该方法执行之后,对request操作,都是无效的

request乱码指的是:浏览器向服务器发送的请求参数中包含中文字符,服务器获取到的请求参数的值是乱码;

response乱码指的是:服务器向浏览器发送的数据包含中文字符,浏览器中显示的是乱码;

一、乱码产生的原因

不管是request乱码还是response乱码,其实都是由于客户端(浏览器)跟服务器端采用的编码格式不一致造成的。

以request乱码为例:浏览器向服务器发送请求,因为浏览器与服务器之间的通信实质上是socket流,所以要先将请求参数(字符)转换成字节,也就是编码过程,服务器接收到请求参数后进行解码(字节转字符),然后封装到request对象中。如果客户端的编码与服务器端的解码不统一,就会导致通过request获取到的请求参数的值是乱码。

二、乱码分类及解决方案
(一)、response乱码
服务器发给浏览器的数据默认是按照ISO-8859-1编码,浏览器接收到数据后按照默认的字符集进行解码后显示,如果浏览器的默认解码字符集不是ISO-8859-1,就出现乱码。

对于response乱码,只需要在服务器端指定一个编码字符集,然后通知浏览器按照这个字符集进行解码就可以了。
有三种方式:
1、response.setCharacterEncoding("utf-8”);//设置服务器端的编码,默认是ISO-8859-1;该方法必须在response.getWriter()之前进行设置
response.setHeader(“contentType”, "text/html; charset=utf-8”);//通知浏览器服务器发送的数据格式是text/html,并要求浏览器使用utf-8进行解码。

2、response.setContentType("text/html;charset=utf-8”);//等同于response.setHeader(“contentType”, "text/html; charset=utf-8”);
而且,它会覆盖response.setCharacterEncoding("utf-8”) ,
在开发中只需要设置response.setContentType("text/html;charset=utf-8”)就可以了。意思是通知浏览器服务器发送的数据格式是text/html,服务器采用utf-8编码,并要求浏览器使用utf-8进行解码。

3、response.setCharacterEncoding(“utf-8”);//设置服务器端的编码为utf-8
response.getWriter().println(””);//要求浏览器使用utf-8进行解码

可以看出,第二种方式是最简便的,这也是我们在开发中最常使用的方式。

(二)、request乱码
从浏览器发起的访问方式有三种:在地址栏直接输入URL访问、点击页面中的超链接访问、提交表单访问。

【 在服务器端,通过request.setCharacterEncoding("XXX”)即可设置服务器的解码为XXX(默认是ISO-8859-1)。
只要服务器的解码字符集和请求参数的编码字符集一致,就不会产生乱码】

1、post方式:表单提交
post方式属于表单提交,参数存在于请求体中,
其编码方式和 <%@ page language=“java” contentType=“text/html;charset=UTF-8”
pageEncoding="GBK%> 中的charset=UTF-8的编码方式一致。
通过request.setCharacterEncoding("UTF-8”)即可解决乱码。

2、get方式:超链接、在地址栏输入URL
get方式提交的参数会跟在请求行中的uri后边,服务器按照默认的iso-8859-1进行解码(注意:是服务器对URI参数进行编码,且一律采用ISO8859-1进行解码),
这时候解决乱码有两种办法:

·办法一:修改服务器端对uri参数的默认编码

在tomcat的server.xml中,
(1)设置<Connector ….>元素的属性URIEncoding="UTF-8”即可。(默认没有设置此属性),指定URI使用“UTF-8”编码方式。
注意:其要求 <%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“GBK” %> 中的charset的值为UTF-8,否则依旧乱码。
【例如:<Connector connectionTimeout=“20000” port=“8080” protocol=“HTTP/1.1” redirectPort=“8443” URIEncoding="UTF-8”/>】

(2)设置<Connector ….>元素的属性useBodyEncodingForURI=“true”,(默认没有设置此属性),意思是URI使用和请求体一样的编码方式,以请求体的为准。
即URI和 <%@ page language=“java” contentType=“text/html; charset=XXX”
pageEncoding=“GBK” %> 中的charset=XXX的编码方式一致。(可以是GBK,也可以是UTF-8)
【例如:<Connector connectionTimeout=“20000” port=“8080” protocol=“HTTP/1.1” redirectPort="8443"useBodyEncodingForURI=“true”/>】

注意:同时设置这两个属性(URIEncoding="UTF-8” 与 useBodyEncodingForURI=“true”),则URI还是使用和请求体一样的编码方式,useBodyEncodingForURI=“true”有效,URIEncoding="UTF-8”无效。

一步到位
1、通过修改server.xml指定服务器对get和post统一按照utf-8解码,即同时设置(URIEncoding="UTF-8” 与 useBodyEncodingForURI=“true”)
2、要求tomcat管理下的所有web应用都要使用utf-8编码,即所有的jsp、html页面都使用utf-8编码。
比如 JSP页面的头信息是这样的:
<%@ page language=“java” contentType=“text/html; charset=utf-8”
pageEncoding=“utf-8”%>

这样,应该就不会出现request和response的中文乱码问题了。

·办法二:回退重编
根据ISO-8859-1进行回退
1、超链接:根据 <%@ page language=“java” contentType=“text/html;charset=XXX” pageEncoding=“XXX”%> 中的charset的值 进行重编,即可得到正常的参数值。

2、在地址栏直接输入URL:根据UTF-8进行重编。

例如:
<%@ page language=“java” contentType=“text/html;charset=UTF-8” pageEncoding=“UTF-8”%>
String name = request.getParameter("name”);//得到乱码
name = new String(name.getBytes(“iso-8859-1”),"utf-8”);//得到正常的name值
注意:name.getBytes();如果不指定编码,默认按照gb2312进行编码。

request和respon
程序员通过request对象获取消息,获取知识(获取情况)根据response回复处理方式
request和respones都是由tomcat创建的

request对象功能,有点像信访等级

1.以下是获取请求行的数据

请求行中包含:

  1. 请求申请的资源
  2. 请求方式
  3. get方法还包含了请求参数
  4. 请求的版本号http 1.0 1.1 2.0

请求消息数据,1.获取请求行
1.getMethod获取请求方式
2.获取请求虚拟目录getContextPath
3/获取servlet路径 getServletPath
4.getQureyString
5.getRequestURL 获取申请访问的地址
6.getRemoveAddr()访问人员地址

URL和URI区别:URI比URL小,但是权限更大,uri是共和国,url是中华人民共和国

request的一些基本操作

package com.company.Demo;

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("/demo02")
public class Demo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
        String method = req.getMethod();//返回请求方式
        System.out.println(method);

        String contextPath = req.getContextPath();//返回虚拟目录
        System.out.println(contextPath);

        String queryString = req.getQueryString();//返回请求参数这里封装了请求参数
        System.out.println(queryString);

        String requestURL = req.getRequestURI();//返回请求的地址

        String remoteAddr = req.getRemoteAddr();//获取客户机的ip地址
        System.out.println(remoteAddr);
    }

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

**

二.获取请求头数据

**
请求头部相对要难操作一些
请求头里面是大量的键值对
方法1.string getHeader(String name)使用这种方法相对于根据键获取值
2.getHeaderNames()相当于一次性获取所有请求头,然后封装成一个链表

这两个可以配合的很好,然后进行遍历
用getHeaderNames获取所有请求头,然后使用getHear根据名字可以进行遍历

package com.company.Demo;

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("/demo02")
public class Demo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
        //获取所有请求头名字
        Enumeration<String> headerNames = req.getHeaderNames();
        //遍历
        //根据名字,获取请求
        while (headerNames.hasMoreElements()){//判断一下,还有没有元素了,只要有就会运行下去
            String name = headerNames.nextElement();//获取name
            String value = req.getHeader(name);//根据请求头提取请求头对应的数据
            System.out.println(name + "---" + value);
        }


    }

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

package com.company.Demo;

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("/demo02")
public class Demo extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);


        String agent = req.getHeader("user-agent");//从数据中获取到访问的浏览器
        if (agent.contains("hrome")){//判断字符串中是否含有一个字段
            System.out.println("谷歌来了");
        }

    }

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

提交一个表单给servlet,注意提交给tomcat上的粗呢路径,毕竟都部署在tomcat上面了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>一个注册页面</title>
</head>
<body>
<form action="/he/demo05" method="post"> <!--action表示把表单提交向哪里,这里表示提交给虚拟路径下,将表单提交给tomcat虚拟路径
下面servlet,交给虚拟路径下servlet处理-->
    <input type="text" placeholder="请输入您的账户" name="user"><br>
    <input type="password" name = "password"><br>
    <input type="submit" value="注册">

</form>

</body>
</html>

**

获取请求体

**
只有post才有请求体

  • 先获取流对象
  • 再从流对象中拿到数据
    获取流对象
    1.getReader获取字符流
    2.getInputStream获取字节流
package web.ServeletDemo;

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.BufferedReader;
import java.io.IOException;
@WebServlet("/demo05")
public class ServleDemo02 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
        BufferedReader br = req.getReader();//使用流读进来
        String line = null;
        if((line = br.readLine()) != null){
            System.out.println(line);
        }
    }

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

*以上方法中,获取请求参数其实是一个很复杂的事情,如果给分成post和get就很烦了,毕竟不太方便是不是,request中其实封装了统一获取请求参数的方法
*
1.获取请求参数方法
string getParameter()根据请求参数获取请求值,请求其实被封装成为键值对了,这种方式返回的是字符串。

String[] getParameterValues()这里这么封装的主要愿意之一,是有的东西,比如复选框给你返回的时候是很恶心的,一个键给你返回好几个值,所以很贴心的的把返回的值给你封装成为一个字符串数组

getParameterNames()返回所有请求的参数名字

getParameterMap()将所有参数都返回封装成为一个键值对

req提取接受来自表单的数据,记住post和get方式没有区别
记住表单action
提交给sERvlet的虚拟位置

package web.ServeletDemo;

import com.sun.prism.shader.Solid_TextureYV12_AlphaTest_Loader;

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.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/demo05")//SERvlet可以通过虚拟路径被找到
public class ServleDemo02 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
        String username = req.getParameter("username");//根据请求参数名字,获取参数值


        //面对复选框,一个name返回了好几个values
        String[] parameterValues = req.getParameterValues("hobby");//返回好几个数
        //返回的数值弄成一个字符串数组
        for (String hobby:parameterValues
             ) {
            System.out.println(hobby);

        }

        Enumeration<String> parameterNames = req.getParameterNames();//返回提交的参数名称
        //得到所有参数的名字,然后,然后使用迭代器,进行便利
        while(parameterNames.hasMoreElements()){
            String name = parameterNames.nextElement();//像个指针一样取到下一个值,取到name
            System.out.println(name);
            System.out.println("------");

            //根据name获取值
            String value = req.getParameter(name);
            System.out.println(value);
        }


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
        this.doPost(req,resp);//doget和dopost获取请求参数是一样的,只要写一个就行了
    }
}

获取请求参数并且封装成为Map集合
post方式,需要进行加密,中文容易乱码
req.setCharacterEncoding = “utf-8”

package web.ServeletDemo;

import com.sun.prism.shader.Solid_TextureYV12_AlphaTest_Loader;

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.BufferedReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;

@WebServlet("/demo05")//SERvlet可以通过虚拟路径被找到
public class ServleDemo02 extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);
        Map<String, String[]> parameterMap = req.getParameterMap();//获取键值对,其中值是string[],为防止复选框
      //将Values存储成为String{},为了防止有复选框
        for (String key:parameterMap.keySet()
             ) {
            String[] value = parameterMap.get(key);
            System.out.println(key + ":");
            for (String values:value
                 ) {
                System.out.println(values);

            }

        }


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
        this.doPost(req,resp);//doget和dopost获取请求参数是一样的,只要写一个就行了
    }
}

内部请求转发

一个SERVLET跳转另外一个SERVLET
还可以把数据封装进去进行转发
getRequestDispatcher()对象请求转发
相当于你到大楼(tomcat)里去找x办公室办事将表格(request)提交给x办公室,x办公室办不了,办公室的人带着这张表格,带着你去到大楼里去找别人给你办理这件事。
1.特点,地址栏并没有跳转,你在大厦门口登记时候写的访问X办公室不会改变
2.你只能访问服务器内部的资源(只能访问一所大厦里资源)
3.仅仅对服务器发送了一次请求

这里提一句域对象:
attribute,相当于你本人往request里面封装进去的数据(键值对形式的)
而getParameter是被提交request的请求参数,一个是程序员封装的数据,另一个是页面去交请求中夹带的数据
request域对象中有
getAttribute
setAttrubute
removeAttribute往域对象中存储一些需要的数据
只能用于一次请求访问多个资源(request内部转发)

package web.ServeletDemo;

import javax.servlet.RequestDispatcher;
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("/demo06")
public class ServletDemo05 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req,resp);
        req.setAttribute("usernamme","wang");//封装一个键值对到req中
        req.getAttribute("usernamme");//通过名字获取值
      

        req.getRequestDispatcher("/demo05") .forward(req,resp);//建立一个连接
        //跳转对象


//用申请到对象,来进行跳转,将自己的两个对象传过去
    }

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

不是IDEA问题,因为创建的不是WEB项目就不会出现这种问题默认charset是utf-8,输出的中文也正常,只有创建的web项目的时候才出现

最后在网上找到好多最后终于找到问题所在,是Tomcat设置问题上,可以这样设置就能解决,添加代码

在这里插入图片描述

最后控制台输入 一切正常了连LOG日志问题都解决了

BeanUtils,将接收到的数据封装成为一个类

  Map<String, String[]> parameterMap = request.getParameterMap();//拿到所有请求参数,并且·封装成一个Map集合
        //根据参数名字可以获取参数
        User loginUser = new User();//将拿到请求体或者请求头的参数封装成User对象
        try {
            BeanUtils.populate(loginUser,parameterMap);//将Map集合里面参数封装到User中去
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

JAVABean用于封装数据
1.类public
2.空参构造
3.成员变量private
4.有setter和getter

beanUtils将传递进来的,Map数据,key值找到包装类的名字,Values封装给对象


版权声明:本文为qq_40707269原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。