一)HttpServlet类:
1)HttpServlet类,咱们自己写的类继承于HttpServlet,重写这些方法的目的就是能够把我们程序员自己的自定义的逻辑给插入到Tomact这个框架中,好让Tomact来进行调用,是依靠于多态,解释多态-----还有Comparator接口,重写CompareTo方法;
2)像这样类似的还有在多线程中,自己写的类继承Thread类,然后再其他线程中,调用start方法,就可以创建线程,然后执行到我们刚才写的代码了;
3)咱们自己写的代码,就是通过继承于这个类,重写这里面的方法,来被我们的Tomact所执性到的;
1)在当前场景中字符串主要是有两个环节,生成,也就是说在IDEA里面通过硬编码的方式把这个字符串写入到进去,还有展示也就是浏览器把这个字符串展示到控制台上面,如果说这两个操作,不能按照统一的编码方式来进行,就很容易出现乱码;
2)正常来说我们在IDEA上面写下的代码的中文都是以UTF-8的格式来进行编码的,那么浏览器也会受到UTF-8格式的响应报文,但是浏览器不会按照UTF-8的格式来进行解析,因为系统是windows简体中文版,默认的系统编码是GBK,浏览器就会默认使用系统编码GBK,浏览器就会按照GBK的方法来进行解析响应,自然也就乱码了
3)如何解决中文乱码问题呢:我们只需要在响应中的header里面加上Content-Type里面注明响应编码UTF-8,浏览器就会按照UTF-8的形式来进行解析,就是显示的告诉浏览器,你不要按照GBK的方式来进行读取了,要按照UTF-8的格式来进行读取,ContentType描述了返回响应的数据格式还有返回的数据编码;
1)HttpServlet处理doGet和doPost请求,我们在这里需要IDEA来编写我们的后端代码,需要VS来编写我们的前端代码;
2)我们在同一个webapp里面,也就是在同一个ContextPath里面,多个Servlet之间关联的路径是不可以相同的,这就会导致Tomact自己就退出了,就是当我们给两个类都进行指定了相同的@WebServlet的路径的时候;
3)关于进程的退出码来说,0表示是正常退出,其他非0值表示异常退出,如果我们直接选择杀死Tomact那么此时的退出码就是-1;
@WebServlet("/method")//这里面的关联要加上/,但是ajax构造请求时不需要加/
public class HelloServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//要保证setContentType在write的前面,否则会失效
//设置中文编码resp.setContentType("text/html;charset=UTF-8");Writer().write("我是一个GET请求");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=UTF-8");Writer().write("我是一个POST请求");}
}
1)我们是在webapp里面创建出一个html文件,这个文件是和WEB-INF是同级目录,是同级的
2)在我们用ajax来进行构造一个Get请求或者Post请求的时候,我们需要在ajax里面写上url路径,里面就要写上@WebServlet中注解的路径
3)这是我们在网络上面点击按钮就可以发送一个Get请求或者是一个Post请求,然后打开Fidder进行抓包,就可以观察到响应报文和请求报文的具体信息;
<script src=".6.0.min.js"integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="crossorigin="anonymous"></script>
<body><input type="button" value="发送Get请求" class="button1"><input type="button" value="发送post请求" class="button2"><script>let buttonget=document.querySelector(".button1");let buttonpost=document.querySelector(".button2");lick=function(){$.ajax({type:"GET",//发送请求的类型url:"method",//相对路径success: function(data,status){console.log(data);console.log(status);}})}lick=function(){ $.ajax({type: "POST",url: "method",body:"request body",success: function(data,status){console.log(data);console.log(status);}});}</script>
</body>
1)在我们的AJAX里面的代码中,路径前面不要加/,不加/是相对路径,相当于当前html所在的路径,访问这个html页面所使用的路径是/Java100/blog1.html,blog1.html所在的路径就是/Java100,相当于是在这个路径上加上一个method,就变成了/Java100/method;
2)如果我们在ajax的url中加上了/,那么此时发出去的/就变成了绝对路径,此时发出去的请求也就变成了/method,此时也就是少了ContextPath,从而会出现404;
3)但是@WebServlet里面,这里面的/是一定要加的,这里面的/和绝对路径相对路径是没有任何关系的,纯粹属于Servlet的硬性要求,加了就对了,不加就不行;
二)HttpServletRequest类
2.1)先向页面上输出一个文字(span标签进行包裹的),在这里面我们要设置的是响应报文的ContentType和响应报文的具体内容,如果说,我们想要返回的页面不是一个HTML,而只是一个简单的文字
那么我们就可以设置header头中的Content-Type=text/plain,charset=utf-8;
@WebServlet("/hello") public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf-8");Writer().write("<span>姓名</span>"); //顺序是不可以颠倒的} }
2.2)这个类就表示一个HTTP请求,理解这个类的前提就是理解HTTP协议的格式,Tomcat把字符串结构的请求解析成了一个结构化的数据,访问里面的属性,得到各个部分的内容,从字符串到结构化数据的过程,称为反序列化;
2.3)HttpServletRequest就对应到一个HTTP请求,HTTP请求里面有啥,这个对象里面就有啥,HttpServletResponse就对应到一个HTTP响应HTTP响应里面有啥这个对象里面就有啥
举一个例子: 127.0.0.1:8080/java100_Servlet/hello?a=10&b=20; 1)String getQueryString() 他得到的是一个完整的queryString 2)Enumeration getParameterNames(),他是得到所有queryString中的key值,例如a,b 3)String getParameter(),这是根据key值,得到value的值,例如参数中传入一个a,返回的就是10(在body中有键值对,也是可以通过这个方法输入Key得到Value 4)String[] getParameterValues(String name),这是处理key重复的情况 这几个方法不光可以操作query string,还可以操作x-www-form-urlencoded这个字符串的dody数据(里面数据的格式和queryString的内容格式是相同的;5)Enumeration getheaderNames(); //获取请求报头,因为请求报头也是键值对结构,得到的是HOST,Referer之类的东西,获取所有Header头中的Key值,此处的Servlet也是把请求头进行了解析,并得到了键值对结构 6)String getHeader(String name) //例如传入一个HOST,得到具体报文的值,根据Header中的Key得到Header中的Value 例如现在有一个GET的HTTP请求: GET/HTTP/1.1 Host:127.0.0.1:8080 User-Agent:xxxxx; Referer:127.0.0.1:8080/login
1)第一个方法getProtocol()所对应的值就是HTTP/1.1和HTTP/1.0
2)getRequestURI(),这里面是I是大写的i;
URL和URI都是表示网络上的一个资源,L->location表示网络上的一个资源的位置
I-->ID相当于是ID,就是表示资源的标识符
3)getContextPath()相当于是得到请求中的第一级路径;
3.1)我们的getQueryString()相当于是得到完整的查询字符串,形如?a=10&b=30;
3.2)下面的这两个方法,相当于是把查询字符串给解析成键值对了;
getParameterNames()相当于是得到所有的key,并以Enum的方式来进行表示;
getParameter()相当于是根据Key得到对应的value;
4)InputStream getInputStream,是获取到body的,这是先获取到一个流对象,先获取到getInputStream的实例,相当于是得到了一个输出流对象,从这个对象中读取数据,其实就得到了请求报文中的body的内容了;
5)像我们的一些其他属性,比如说QueryString,Header我们都是直接拿到字符串这样的类型,但是因为body中的内容可能要更长一些,我们就当前没有通过字符串的方式来进行获取,而是直接通过流对象的方式来进行获取;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//我们调用一下刚才我们涉及到的几个关键性的API,并把最终结果给组织到一个html里面,并作为响应的body,我们希望把API执行的结果放到StringBuilder里面StringBuilder stringBuilder=new StringBuilder();stringBuilder.append("<h3>首行部分</h3>");stringBuilder.Protocol());//得到协议名和版本stringBuilder.append("<br>");stringBuilder.Method());stringBuilder.append("<br>");stringBuilder.RequestURI());stringBuilder.append("<br>");stringBuilder.ContextPath());stringBuilder.append("<br>");stringBuilder.QueryString());stringBuilder.append("<br>");stringBuilder.append("<h3>得到所有的header部分</h3>");//先通过getHeaderNames()方法获取到所有的KeyEnumeration<String> HeaderNamesHeaderNames();while(HeaderNames.hasMoreElements()){String HeaderKeyElement();String HeaderValueHeader(HeaderKey);stringBuilder.append(HeaderKey+":"+HeaderValue+"<br>");}//把这个stringBuilder对象转换成String对象写入到HTTP响应报文的body里面resp.setContentType("text/html;charset=utf-8");//此处应该写成text/html而不应该写成test/html,如果这样是不能被浏览器所识别的Writer().String());}
}
1)获取GET请求中的参数
1)获取到QueryString中的参数,这里面是程序员自定义的内容,里面的每一个键值对的键和值都是程序员自己所定义好的(例如说查询的时间戳),如果说getParameter方法中传入的Key对应的Value不存在,那么就会返回一个空值null;
2)浏览器的请求类似于说:127.0.0.1:8080/java200/method?classID=10&userID=20
Integer:parseInt/valueOf
所以说很多时候我们要对query string进行判定是否存在,判定代码就要写成这种格式
if(userID==null||userID="")//参数不存在
{
}
得到HTTP请求中的queryString部分,我们可以自己提前约定好请求中的querystring中的格式
@WebServlet("/method")
public class HelloServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String userIDParameter("userID");String classIDParameter("classID");Writer().write(String.format("userID=%s classID=%s",userID,classID));}
2)获取POST请求中的body格式的数据:
2.1)一般来说,POST请求中的自定义数据都是放到body中的,通过获取getInputstream对象来得到HTTP格式中的body中的数据;
2.2)POST中的body类型又分为好几种格式;
1)application/x-www-form-urlencoded类型,正文格式类似a=10&b=20,这是类似于queryString中的格式; 2)mutlipart/form-data,这种格式比较复杂,是用来提交文件,或者是上传文件 3)application/json{a=10,b=20 }
1)获取到application/x-www-urlencoded的body参数,这是和获取到Get请求中querystring的方法是一样的
通过form表单来构建一个HTTP请求
<form action="post" method="POST">---->@WebServlet()中的注解 <input type="text" name="classID"> <input type="text" name="userID"> <input type="submit" value="提交"> </form>
获取到第一种类型中的body参数,这是idea中的代码,还需要构建根据ajax或者form表单一个POST请求 约定的请求格式 @WebServlet("/post") public class HelloServlet1 extends HttpServlet{@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //假设我们前端的参数传递的也是userID=90&classID=100resp.setContentType("text/html;utf-8");String str1Parameter("classID");String str2Parameter("userID");Writer().write(String.format("userID=%s classID=%s",str2,str1));} }
上面写构造POST请求是通过form表单来构建的,也可以通过ajax的方式来构建;
<input type="button" class="button" value="构建一个post请求"> 当我们点击这个按钮的时候,就会触发一个POST请求 <script src=".6.0.min.js"integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="crossorigin="anonymous"></script><script>let button=document.querySelector(".button");lick=function(){$.ajax({type:"POST",url:"post",ContentType:"application/x-www-form-urlencoded", //注意这里面的类型要写对data: "classID=30&userID=20", //注意这里面写的键值对的名字是bodysuccess: function(data,status){console.log(data);console.log(status);}}); } </script>
注意:前端的静态页面blog.html是存放在webapp目录下面的,也就是静态文件是和WEB-INF是处于同一级路径下面的,而不是把这个html文件存放在WEB-INF目录下面,如果你把这个静态资源文件放错位置了,那么一定会出现404
2)获取第三种JSON方式的body,运用字节流的方式来获取,它的形式是json形式的字符串
1)创建出一个Body为json格式的POST请求,注意构造json格式的字符串,只能使用ajax的方式来构建;
2)在POST请求中发送JSON格式的数据,在AJAX里面键是data,传过去的是一个JSON对象,所以我们要提前进行创建一个对象,里面的形式类似于JSON格式的键值对;
3)我们还要注意,我们在前端页面创建好里面是JSON格式键值对的对象之后,我们不可以直接写引用名,我们传过去的应该是一个字符串,JSON.stringfy(引用名);
4)我们先输入一个地址,http:127.0.0.1:8080/Java200/hello.html打开一个HTML界面,然后点击按钮会根据AJAX方式,给服务器发送一个HTTP的POST请求,请求报文就是我们在前端页面发送的data数据,服务器拿到body之后,整个进行读取,再把这个数据返回在body里面
前端代码: <input type="button" value="发送一个POST请求" class="POST"><script> let POST=document.querySelector(".POST"); let body={userId:343021637,password:1238381, }lick=function(){$.ajax({type:"POST",url:"post",contentType:"application/json",data:JSON.stringify(body),success:function(data,status){console.log(data);console.log(status);}}); }</script>
后端代码:@WebServlet("/post") public class HelloServlet extends HttpServlet {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String body=ReadBody(req);Writer().write(body);}public String ReadBody(HttpServletRequest req) throws IOException {InputStream inputStream= InputStream();Scanner scanner=new Scanner(inputStream);StringBuilder stringBuilder=new StringBuilder();while(scanner.hasNext()){String next= ();stringBuilder.append(next);}return new String(stringBuilder);} }
解析JSON格式的数据:
我们可以直接在中央仓库里面搜索jackson即可,直接用Jackson Databind即可,直接使用2.13.1版本即可;然后把这段代码直接放到l中;
<!-- ./jackson-databind --> <dependency><groupId>com.</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version> </dependency>
Json格式字符串解析的过程:
我们在JAVA这里所做的核心工作就是:需要使用Jackson,把请求中的body格式的数据读出来并转化成JAVA中的对象
//通过这个类来表示解析后的结果 class JsonData{public int classID;public int userID; } @WebServlet("/post") public class HelloServlet1 extends HttpServlet{@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String Body=readbody(req);ObjectMapper mapper=new ObjectMapper();JsonData jsonDataadValue(Body,JsonData.class);//其实这个实例创建的过程就相当于把Body也就是JSON字符串成了一个java对象//打印结果String result=String.format("classID=%d,userID=%d",jsonData.classID,jsonData.userID);Writer().write(result);}public String readbody(HttpServletRequest req) throws IOException{ //读取body需要先通过req getInputStream得到一个流对象,从这个流对象中来读取InputStream inputStream= InputStream();//先通过contentLength来得到body中的字节数int contentlengthContentLength();//获取body中的字节数,主要是想创建出一个contentLength大小的缓冲区byte[] arr1=new byte[contentlength];ad(arr1);return new String(arr1,"utf-8");} }
后端的这个readValue方法:
1)这个方法主要是读取body中的请求,然后使用ObjectMapper来解析成所需要的对象
readValue就是把JSON格式的字符串转化成JAVA中的对象
2)第一个参数是我们要对哪一个字符串进行转换,这个第一个参数可以填写一个String,也是可以填写一个InputStream对象,还可以填写一个File对象;
3)第二个参数是说我们要把这个JSON格式的字符串,转化成哪一个JAVA对象;
ReadValue是如何完成转换的?
1)先把getInputStream()对应的流对象里面的数据都进行读取出来;
2)针对这个JSON格式的字符串来进行解析,把一个字符串转化成一个键值对
key:username;value:123456;
key:password;value:778896;
3)遍历这个键值对,依次获取到每一个key,根据这个key的名字,依次和我们自己创建的类的属性名字进行对比,看看有没有匹配的名字,就是拿着这个key名字username到JsonData类里面找有没有属性名叫做username;
4)如果发现有匹配的属性,如果有就把key对应的value这个值赋值到该JsonData中的username的属性中,在赋值的过程中也会进行类型转换,字符串(String)转换整数(int);
5)如果说没有匹配的属性,就进行跳过,取下一个Key,当我们把所有的键值对遍历之后,JsonData对象也就被构建的差不多了;
6)在这里我们是如何拿到这里面的属性名字呢?
我们就从JsonData.class里面拿,拿到了类对象,就可以拿到这个类的关键信息了,就可以知道每一个属性叫做什么名字了,就可以进行对比了;
7)根据这个类对象,拿到类里面的关键信息,就叫做反射;
8)如果说key值和属性名字不匹配,那么不会成功的进行解析;
<script> let body={classID:100,userID:200}let button=document.querySelector(".button");lick=function(){ $.ajax({type:"POST",url:"method",data:JSON.stringify(body),contentType:"application/json;charset=utf-8",success:function(data,status){console.log(data);console.log(status);} })} </script>
上面系统地完成了从JSON格式的字符串到Java对象的解析过程,下面我们来进行分析一下:
class JsonData{public int classID;public int userID; }JsonData jsonDataadValue(Body,JsonData.class); {"userID":100,"classID":10}
1)对于像POST这样的请求,AJAX就允许是用这样的data属性来构造请求的body部分,其实我们在data中构建的内容,本质上是一个JS对象,我们还需要把这个JS的对象通过JSON.stringfy()的方式,来把JS对象转化成一个字符串,这个字符串就正式按照JSON格式的方式在网络上面进行传输;
2)我们点击提交之后,可以看到在浏览器的控制台上面,就打印出来了服务器的返回的响应数据,因为当前我们使用的是AJAX的方式来进行提交数据,这个操作默认不会产生页面跳转,就和我们的form表单使用风格差别很大;
这种构造请求的方式也是可以的;
小结:我们使用HttpServletRequest最常用的工作就是获取请求中的参数;
1)GET请求中的query string通过getParameter方法;
2)获取body,application/x-www-form-urlencoded中的参数也是用到getParameter方法;
3)获取(application/json)的内容,先把整个body字符串读取出来,然后再使用json库来进行解析;
使用postman来构建HTTP请求
1)我们直接点击workspaces,想要创建出一个Body格式是JSON的POST请求,点击raw,在最右边选择JSON,在下面的空白处就可以写具体的格式了,这里面的路径不要写错;
2)Params是专门用来设置QueryString的,在Headers里面我们也是可以设置一些自定义的Header头,还可以看到自己系统自带的一些Header头;
3)HttpServletResponse对象的一些方法
1)HttpServletRequest里面的内容是由客户端进行构造的,服务器需要做的事情就是获取到这里面的内容,天生就是用来读的;
2)HttpServletResponse里面的方法都是带有set字段,里面的内容,是服务器构造的,是要返回给客户端的
Servlet里面的doXXX方法的目的就是根据请求计算得到响应,然后把响应的数据设置到HTTPServletResponse对象里面,然后我们的Tomact会把这个对象按照HTTP协议的格式转化成一个字符串,并且通过Socket返回给浏览器;
1)void setStatus(int src)是给响应设置状态码
2)void setHeader(String name,String value)
这是设置一个给定名称的header,如果name已经存在,就覆盖掉原来的新值;
3)void addHeader(String name,String value)
添加一个带有给的名称和值的header,如果name已经存在,不覆盖旧的值,并创建出一个新的键值对
4)void setContentType(String type)设置发送到客户端的相应的内容类型
5)void setCharacterEncoding(String charset)设置发送到客户端的字符编码类型
6)void sendRedirect(String location)使用指定的重定向位置的URL发送临时重定向到客户端
7)Printer getWriter()向body中写一个文本格式数据就是以字符流为基本单位进行操作的
8)OutputStream getOutputStream(),向body中写入一个二进制格式的数据
7方法和8方法都是可以获取到输出流对象,得到输出流对象之后,我们就可以向相应的报文body中写数据了
1)对于HTTP响应来说,header中的key并不是唯一的,有些key可以重复出现,最典型的就是Set-Cookie属性;
2)如何构造一个重定向响应呢,只需将状态码设成302,在header中设置location就可以了,但是这两个过程都可以用一个方法来代替,就是void setRedirect(String location)即可
示例一:设置状态码
1)也就是说让用户输入一个请求,请求在queryString中设置一个参数,就表示相应的状态码,然后再根据用户的输入,返回不同的状态码的响应;
2)我们还需要注意一个事情通过getParamter()方法中获取到的参数的返回值是一个字符串类型
3)我们服务器返回的状态码,只是在告诉浏览器当前返回的响应是什么样子的状态,并不会影响浏览器去解析body中的数据格式的内容;
B站上面的返回的404的body是一个正常的html界面
resp.setStatus(404); resp.setContentType("text/html;charset=utf-8"); Writer().write("生命在于运动");
@WebServlet("/status")
public class HelloServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf-8");String statusStringParameter("status");if(statusString==null||statusString.equals("")){Writer().write("当前你写的querystring中的status参数缺失");return;}resp.setStatus(Integer.parseInt(statusString));Writer().write("status:"+statusString);}
}
示例二实现让页面自动刷新的案例:
1)我们实现一个程序,让浏览器每秒钟自动刷新一次,并显示当前的时间戳;
2)我们可以直接HTTP响应中在header中设置一个Refresh,值就是刷新的间隔时间,比如说文字直播,要自动实时刷新页面;
@WebServlet("/status")
public class HelloServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html;charset=utf-8");//这表示在header设置一个属性为Refresh,参数是1s,表示每隔1s刷新一次resp.setHeader("Refresh","1");//这里面的参数都是字符串//直接显示一个毫秒级时间戳,来观察动态页面的变化long time=System.currentTimeMillis();Writer().write("time :"+time);}
}
示例三:设置一个重定向代码,当我们输入文件路径之后,就是又让他跳转到一个新的页面,呼叫转移,所以我们希望直接输入路径的时候,就直接跳转到搜狗主页了,就类似于文字直播;
@WebServlet("/status")
public class HelloServlet1 extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//resp.setStatus(302);
//resp.setHeader("Location","");//也可以这么写resp.sendRedirect("");}
}
本文发布于:2024-02-08 19:48:35,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170739304268474.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |