javaweb学习笔记


javaweb为java的web方面主要的书记应用为jsp等

http请求

http协议为互联网传输信息的一种规则,与之类似的还有ftp这样的协议。

http特点
  • http在传输的时候会以服务端客户端的模式进行传输。
  • http的客户端传输请求时只用传输请求的URL,请求传输的方法常用的为GET和POST两种,这两种方法决定了客户端与服务端的联系不同
  • http允许传输任意类型的对象,传输时的类型会在传输的数据包中的Content-Type处表明,现在默认都为*/ *
  • http不会像TCP这样建立一个完整的通讯连接,它每次只会处理一个请求即,在处理完客户端发来的一个请求之后并收到客户端的应答之后会断开连接。
  • 在http1.1版本(也就是我们现在经常见到的版本)支持基于TCP的长连接,即实现请求和响应的并发性,不会造成后一个请求等待前一个请求相应完毕之后再进行处理。
  • http对于连接是没有记忆性的即无状态,大致意思为,如果后来的连接需要用到前边连接的数据,但是http又不会记住数据,所以就只能重传,对于需要前边连接信息的传输连接这可能会增加传输的数据量,但对于不需要的则会提高应答效率。

javaweb之环境配置

我的javaweb是搭建在idea(配置环境是真的阴间),本来在idea上用默认的javaweb模块以为能成,结果老是404,好不容易dbug成功又成500,改了改又成404(花了我一下午时间,当时人就麻了),索性自己只能先建一个java项目再自己加模块了。

下边为创建一个javaweb项目的步骤:

新建(new)——>项目(project)

直接什么库和框架也不选直接下一步

这里也不要选它所提供模块

这里写的时你自己的项目名字,和你项目所存储的位置

到这里我们算是创建了一个java项目,接下里就是对其加上web功能

这里我们需要在所生成的WEB-INF目录下自己创建两个目录:classes和lib

修改输出目录和测试输出目录为我们刚才创建的classes目录

在设置好输出目录之后需要我们在添加依赖,即我们javaweb所要用到的一些api,由于我的javaweb项目是搭建在tomcat服务器上,所以我直接把tomcat的lib目录加上去(直接解决缺少依赖问题)。

接下来是对访问的一些配置

这里我自己感觉选默认的jrf没有自己的好用,

在四号位是在你本地的浏览器中访问路径,我自己不是特别想整了,接下来如果想要写java代码需要在src目录下创建包和类进行写自己的项目。

servlet

servlet是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。————引自菜鸟教程

我的理解为:servlet便于将从http server得到相关对象传递给服务器,servlet主要运行在服务端,由服务器调用执行,可以生成动态的web页面,同时它也是一种java类,我们能够从servlet中得到http请求中的get,post,url等数据信息,同时再对这些数据进行相关的操作。

 @("/访问路径")   //一定要加“/”,否则会出现报错
servket的生命周期

一般的一个servlet分为init(),service(),destroy(),三个阶段,

  • init():

对一个servlet对象进行初始化,只在第一次调用servlet对象时会调用此方法,后续调用该servlet对象时则不再调用此方法。

  • service():

service方法为执行实际对servlet请求响应的方法,每一次在接收一个sevlet请求时若是调用已经存在的sevlet对象时都会调用此方法,每次调用时都会新产生一个线程调用该服务。其中service具有一个传入对象request和返回对象response,每当service被实例化时,这两个对象都会被实例化。

  • destroy():

destroy方法为对一个servlet对象进行销毁的方法,在一个servlet对象的生命周期中只会被调用一次,通常用于关闭数据库连接等,停止进程。

一个完整servlet请求的过程

客户端向web服务器发送一个http请求,web服务器接受此请求并将此请求转发给servlet容器,servlet容器再找到相关servlet并对request和response进行实例化,然后再调用service方法,调用后再从已经实例化的request对象中得到请求的数据,再根据请求进行相关操作,将最后得到的结果进行封装返回给response对象,后将response对象返回给服务器,再由服务器将响应的结果返回给客户端。

以上为servlet容器中存储由所请求的servlet对象,若没有则会将得到的动态检索先存储再容器的地址空间中,再在servlet容器中利用init方法创建相关的servlet对象,然后再进行对request和servise进行实例化,再进行下一步操作。

HttpservletRequest对象

当客户端向服务器发送一个http请求时,tomcat会将请求信息封装到HttpservletRequest对象中,然后将此对象作为service的传入的参数进行相关操作,常见操作为:

req为我们的的一个完整的request请求,

getRequestURL方法为我们request的请求中的完整的URL

getRequestURI方法为我们request的请求中所访问的资源路径,即在访问端口后访问参数前的的内容

getQueryString方法为我们request的请求中所得到的访问参数,即我们经常性所用到的GET参数,不过此方法只能得到?这一参数代表符后边的全部,如果存在多个参数,它就会将所有的参数全部得到(包含参数名)

getMethod方法会返回request的请求方式,这里我用的是GET方式

getProtocol方法为判断http版本

getContextpath判断当前request所访问的站点名

若想要在浏览器中能够访问到这个servlet类则需要在public class类上添加注解格式为:

请求转发

先上例子:

package com.test.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/demo02")
public class Servlet2 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String name = req.getParameter("uname");
        System.out.println("参数为:"+ name);
        //请求转发的具体代码
        req.getRequestDispatcher("index.html").forward(req,resp);

    }
}

我们先访问login.html,它会向demo02也就是servlet02.java发送请求,servlet02又将此请求转发至index.html,这样的过程称之为请求转发,在请求到servlet2.java之后的过程中客户端的URL为demo02?uname=wqewe而非我们所想的index.html,这也是请求转发的特点之一,相当于对于真正的页面做了隐藏。主要用于web页面的防护,在登陆时的检测。需要注意的是请求转发的整个过程中客户端只发送了一个请求,而在服务器中则是从最开始的servlet接收者转发至其它的servlet且有可能转发多次,最后再由最后接收的servlet向客户端发送回应.

在以上例子中我所举的例子中只有一个servlet,对于有多个servlet例子如下(在上边例子的基础上加了一个servlet3.java):

我们可以看到已经成功调用了servlet3.java但是我们自己客户端的URL为:http://localhost:8080/demo02?uname=www

这也表现了请求转发在转发至服务器最开始的servlet之后不会改变客户端URL的特点。

同时,servet3中传入的参数为servlet2中传入的参数req和resp一致。

request作用域

我们在从客户端向服务端发送请求之后,服务端再做处理一系列操作之后得到最后的结果,但是客户端是怎么得到结果的(服务端我们使用的是java代码可是客户端是看不懂Java代码的(例如java里边的数组之类的)),这时候就需要用到request作用域来进行相关的转变,最后拿到后台响应的数据。

例子如下:

Servlet3.java:

package com.test.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
@WebServlet("/demo03")
public class Servlet3 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("wwwwww");
        //req.getRequestDispatcher("index.html").forward(req,resp);
        String uname = req.getParameter("uname");
        if (!"admin".equals(uname)){
            req.setAttribute("msg","用户名不对");
            req.getRequestDispatcher("/login.jsp").forward(req,resp);
        }else{

            req.getRequestDispatcher("/index.html").forward(req,resp);
        }

    }
}

login.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


账号 <%=request.getAttribute("msg") %>

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>后台</title>
</head>
<body>
<h1>hello world</h1>
</body>
</html>

最后根据输入的数据是否为admin来判断是否请求转发。

Httpservletrespond对象

当servlet对一个请求响应完毕后会将返回的结果赋值给respond对象,对客户端的请求的响应需要我们获取输出流,respond的输出流有两种方式:

getWriter() 只获取字符串类型的输出流

getOutoutStream() 获取字节类型的输出流,能够输出任何类型

输出流的数据到客户端会被客户端浏览器进行解析得到最后的结果。

输出流为字节流:

package com.server.respond;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;

import java.io.IOException;
@WebServlet("/server01")
public class Servlet01 extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        ServletOutputStream out = res.getOutputStream();
        out.write("我带你们打".getBytes());
        out.flush();
        out.close();
    }
}

输出流为字符串:

import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;

@WebServlet("/server01")
public class Servlet01 extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html;charset=UTF-8");
        PrintWriter writer =res.getWriter();
        writer.write("我带你们打");
        writer.write("hello world");
        writer.flush();
        writer.close();
    }
}

对于这两种输出流都有可能出现中文字符乱码的情况,可以用

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

通过设置服务端和客户端的编码格式修复。同时也因为我们调整了编码格式,所以也可以在输出的时候对某些输出进行标记为标题等。

如果编码格式书写错误会导致客户端因为无法识别当前编码格式而导致下载文件。

同时不能同时调用这两种输出流,会因它们同时需要调用res这一返回对象而产生冲突。

重定向

我们在有时候访问网站时会出现302状态码,这表明我们所访问的资源被进行了重定向,通常我们都会发现最后的URL会和我们刚开始所访问的不一样。

至于具体的流程如下图

重定向和请求转发的区别:

1.重定向的URL会发生变化而请求转发不会

2.请求转发只会发送一次请求,且对请求的相关操作在服务器内部的servlet容器中实现,最终为一个request域且数据在域中共享,重定向会发送两次请求,会分为两个request域两个域之间数据不共享。

3.请求转发主要的工作在服务器内部的servlet容器中,重定向则是一个完整的服务器和客户端交互的过程。

这里也可以举一个贴近现实的例子:

比如我有一道题不会用微信去问朋友,这个朋友他自己也不太会,就去问了另外一个人最后得到了答案,然后朋友将答案最后给了我,这是请求转发的实际模拟,还有一种情况就是我向朋友去问题,他表示不会但是他给了我一个会的人的微信,让我去问他,最后得到了答案,这就是重定向的实例。

以下为重定向的代码:

Servlet02:

package com.server.respond;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/server02")
public class Servlet02 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.sendRedirect("/server01");
        System.out.println("已经进行了重定向");
    }
}

Servlet01:

package com.server.respond;

import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;

import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;

@WebServlet("/server01")
public class Servlet01 extends HttpServlet {
    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        res.setCharacterEncoding("UTF-8");
        res.setContentType("text/html;charset=UTF-8");
        PrintWriter writer =res.getWriter();
        writer.write("我带你们打");
        writer.write("<h1>hello world</h1>");
        writer.flush();
        writer.close();
    }
}

cookie对于我们来说可以说是不陌生的东西了,在java web中我们可以利用相关的类来进行cookie的创建和获取,

具体代码如下:

package com.server.respond;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
@WebServlet("/server10")
public class Servlet03 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie www = new Cookie("name","wdnmd");
        resp.addCookie(www);
    }
}

我们对父类的的service方法进行了重写,然后创建了一个cookie类型的变量www其中www的name参数的值为name,value参数的值为wdnmd,然后利用resp对象中的addcookie方法将创建完毕的cookie发送给客户端。

对于cookie的获取方法如下:

代码如下:

package com.server.respond;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/server05")
public class Servlet04 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Cookie[] cookies = req.getCookies();
        if (cookies != null&& cookies.length!=0){
            for (Cookie cookie:cookies){
                if ("name".equals(cookie.getName())){
                    System.out.println(cookie.getValue());
                }
            }
        }
    }
}

我们在对service方法重写之后创建了一个cookie类型的数组变量cookies通过req对象的getcookies方法来获取cookie,然后对胡哦去的cookie进行为空判断,在利用for循环创建一个cookie类型的变量cookie来进行对cookies数组中的值进行获取,再在循环体内部对cookie所获得的name参数的值判断是否为name,如果是则利用equals函数获取cookie变量中value的值。

cookie的存活时间

对于cookie的存活时间一般有三种方式,而这三种方式同一个名为maxAge的参数相关,

maxAge为0:表示立即删除此cookie;

maxAge为负整数:表示再关闭浏览器时删除此cookie;

maxAge为正整数n:表示在当前时间的基础上加上n秒,且cookie的存活时间为n秒。

具体语法为:

//创建cookie
Cookie www = new Cookie("name","wdnmd");
//设置cookie的存活方式
        www.setMaxAge(-1);
//发送cookie
        resp.addCookie(www);
cookie中添加中文

cookie中默认不支持中文,但可以通过对向cookie中添加的内容进行编码的方式来进行中文的添加。

具体的编码代码为:

String  name ="名字";             
String value ="张三";          //定义自己需要向cookie中添加的中文内容
name = URLEncoder.encode(name);
value = URLEncoder.encode(value); //对添加的内容进行URL编码
Cookie www = new Cookie(name,value); //生成cookie
//www.setMaxAge(-1);
resp.addCookie(www); //向客户端发送cookie

接收cookie的中文内容的解码代码为:

String name = URLDecoder.decode(cookie.getName());
String value = URLDecoder.decode(cookie.getValue());
//定义两个String类型的变量来接受cookie中的name和value两个参数解码后的值
System.out.println(name + "," + value);

对于name相同的cookie,最终的结果为最后的cookie会将前边所有相同name的cookie的value进行覆盖(前提时cookie的来源相同)

其它项目或资源对同一cookie的访问

我们有时会对同一cookie进行一些访问限制,即不同的项目之间不能得到对方的cookie,或者有时我们需要得到其他项目的cookie,所以此时就需要我们对cookie的访问进行一些限制了。

具体代码为:

允许所有项目访问:

Cookie cookie = new cookie("xxx","xxx"); //创建一个新的cookie
cookie.setpath("/"); //允许所有项目访问此cookie
resp.addCookie(cookie);//发送cookie

只允许当前项目下的资源访问:(以当前项目为server01为例子)

Cookie cookie = new cookie("xxx","xxx"); //创建一个新的cookie
cookie.setpath("/server01"); //只允许server01项目访问此cookie
resp.addCookie(cookie);//发送cookie

只允许当前项目下的某一路径下的资源进行访问:

Cookie cookie = new cookie("xxx","xxx"); //创建一个新的cookie
cookie.setpath("/server01/www"); //只允许server01项目下的www路径下的所有资源访问此cookie
resp.addCookie(cookie);//发送cookie

只允许特定项目下的某一路径下的资源访问:

Cookie cookie = new cookie("xxx","xxx"); //创建一个新的cookie
cookie.setpath("/server02/www"); //只允许server02项目下的www路径下的所有资源访问此cookie
resp.addCookie(cookie);//发送cookie

session

首先对于session的产生,拿我们日常生活的例子来说就是,我们在访问京东或者淘宝时,在首页登录之后开始闲逛,每当我们点开不同的商品时页面的URL会发生跳转,标示着我们每次的request请求的作用域是不以一样的,在前边我们知道不同的作用域之间是无法进行互通的,且不同的http请求之间是无联系的,这样就造成了如果我们每点一次商品就需要我们重新登陆一次,虽然有cookie,但是由于cookie的存储大小很小只有40kb左右,且cookie的存储数量有限,同时cookie本身的不安全性,这样就需要一种新的技术session。

对于服务器来说每一个和它连接的客户端都是一个session,相对于request的作用域,session的作用域更为宽广,而session作用域的有效范围则是一次会话过程,会话可以理解为是在一段时间内一个客户端所有request请求的集合。只要session会话未结束则在此期间的内容可以共享,若会话结束,则会清空此次会话的所有内容。

session的作用就是标识一次会话,同时也是为了在一次会话期间能够共享数据。

而对于一次会话我们是如何拿到session对象,可以同宫request.getSession这个方法来拿到sesion对象,此方法的大概逻辑为拿到当前会话的session对象,没有session对象则会创建一个session对象。

HttpSession session = request.getSession();

session的作用是标记一次会话,那么标记会话的标记则是JSESSIONID,一般来说JSESSIONID是在cookie中保存的。

我们的每一次请求在到达服务器之后,服务器会首先查看此请求中是否有name的值为JSESSIONID的cookie,如果没有服务器就会认为这是一次新的会话,会自己生成一个session对象,同时也会生成一个特定JSESSIONID作为此次会话的标识。

如果我们的请求中包含了JSESSIONID,那么服务器会根据JSESSIONID来进行查找,如果没有找到所收到的JSESSIONIDD的session对象,服务器则会重新创建一个session,并保存,然后将生成的JSESSIONID保存到cookie中返回给客户端。如果找到了对应的JSESSIONID但是没有找到对应的session对象,服务则会重新创建一个session,并将session保存起来,并把生成的JSESSIONID保存到cookie中发送给客户端。

如果我们的请求中有JSESSIONID的cookie,且服务器能够根据此cookie找到对应session对象,则会接着session对象进行会话。


文章作者: lemon-fan
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 lemon-fan !
 上一篇
vulnhub-doubletrouble vulnhub-doubletrouble
一个月没怎么学习,只能先拿vulnhub练练手顺便给自己扩展一下思维和认知 信息收集在信息收集之前我先说一句,vmware真的哈皮,讲一下我在这里所遇到过的vmsare的一些错误,我们配置虚拟机的网络时要先看好自己当前上网的网卡是哪个,把虚
2021-09-23
下一篇 
java学习笔记 java学习笔记
java认知java为编译性的语言,应用很广泛,java对于类型具有很严格的限制,是一种强类型的语言 //定义一个公开的类Start public class Start { //定义main函数默认参数必须为String[] ar
2021-07-29
  目录