WebServer【笔记】

1.WebServer主类

  • WebServer是一个web容器,模拟Tomcat的基础功能。
  • Web容器的两个主要任务:
  • 1:管理部署在容器中的所有网络应用(WebApp),每个网络应用就是我们俗称的一个"网站。"
  • 它通常包含页面,处理业务的代码,其他资源等等
  • 2:负责与客户端(通常是浏览器)完成TCP链接,并基于HTTP协议进行交互,使得客户端可以
  • 通过网络远程调用容器中的某个网络应用

首先先构建起初始框架:

在这里插入图片描述

在这里插入图片描述

public class WebServerApplication {
    private ServerSocket serverSocket;
		
	 /**
     * 构造器
     */
    public WebServerApplication() {
        try {
            System.out.println("正在启动服务端...");
            serverSocket = new ServerSocket(8088);//申请服务端口
            System.out.println("服务端启动完毕!");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 由于main()方法是静态方法,不利于调用非静态资源,所以设计一个start()方法
     */
    public void start(){
        try {
            System.out.println("等待客户端链接...");
             //监听服务端口,一旦一个客户端通过该端口建立链接则会自动创建一个Socket
            //并通过该Socket与客户端进行数据交互
            Socket socket = serverSocket.accept();
            System.out.println("一个客户端链接了!");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    
    public static void main(String[] args) {
        WebServerApplication server = new WebServerApplication();
        server.start();
    }
}

在浏览器中用http://localhost:8088进行测试,如果在控制台显示“一个客户端链接了”,则此处操作成功!
在这里插入图片描述

HTTP协议要求浏览器连接服务端后应当发送一个请求,因此需要实现读取请求并输出到控制台来了解请求的格式和内容

实现:
由于服务端可以同时接收多客户端的连接,因此与聊天室相同,主线程仅负责接受客户端的连接,一旦一个客户端连接后则启动一个线程来处理。
1:在com.webserver.core下新建类:ClientHandler(实现Runnable接口),作为线程任务。工作是负责与连接的客户端进行HTTP交互
2:WebServerApplication主线程接收连接后启动线程执行ClientHandler这个任务处理客户端交互
3:在ClientHandler中读取客户端发送过来的内容(请求内容)并打桩输出

由于此时服务端只能与一个客户端进行链接,所以设置一个线程任务,负责与指定的客户端完成Http交互。

public class ClientHandler implements Runnable{ //客户端处理器
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {

    }
}

在WebServer主类中设置线程接收客户端:

public void start(){
        try {
            System.out.println("等待客户端链接...");
            Socket socket = serverSocket.accept();
            System.out.println("一个客户端链接了!");
            //启动一个线程负责与该客户端交互
            ClientHandler handler = new ClientHandler(socket);
            Thread t = new Thread(handler);
            t.start();//这个start()是启动线程的start()方法
            
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

此时因为工作还不完善,所以暂时不设置死循环,只接受一个链接,避免链接上过多客户端而没有反馈信息或操作。

转回到ClientHandler,在run()方法中建立输入流,读取从浏览器反馈回来的信息(读取请求):

/**
 * 该线程任务负责与指定的客户端完成Http交互
 */
public class ClientHandler implements Runnable{ //客户端处理器
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //由于在接收到的数据不会完全是文本数据,所以此处不应该设置为字符流
            InputStream in = socket.getInputStream();
            int d;
            while ((d = in.read())!=-1) {
                System.out.print((char) d);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } 
}

启动服务端,在浏览器中用http://localhost:8088
在这里插入图片描述
可以在控制台看到一堆返回信息,这些信息是浏览器链接时发送的一些请求。

注意:此处要是看到一片乱码,有可能是地址输成了https开头。

接下来要做得事情如图所示:

  • 设置一个线程任务负责与指定的客户端完成HTTP交互
  • 每次HTTP交互都采取一问一答的规则,因此交互由三步来完成:
  • 1:解析请求
  • 2:处理请求
  • 3:发送响应
    在这里插入图片描述

1.解析请求:
HTTP协议要求客户端连接后会发送一个请求,每个请求由三部分构成:
请求行 消息头 消息正文

首先请求行和消息头有一个共同的特点:都是以CRLF结尾的一行字符串.
因此先实现读取一行字符串的操作,测试将请求行读取出来并进行解析.之后可以再利用这个操作完成消息头的读取并解析.

在这里插入图片描述

实现:
在ClientHandler中完成读取请求行的操作.

public class ClientHandler implements Runnable{ //客户端处理器
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //由于在接收到的数据不会完全是文本数据,所以此处不应该设置为字符流。
            //又字符流存在缓冲区,不适合一行一行读取的情况,可能会丢失数据。
            InputStream in = socket.getInputStream();
            //由于String的连接性能差,所以此处采用StringBuilder/StringBuffer
            //但因为这里不会出现并发安全问题,所以选用StringBuilder
            StringBuilder builder = new StringBuilder();
            int d;
            /*
               请求行是一行字符串,以连续的两个字符(回车符和换行符)作为结束这一行的标志。
               回车符:在ASC编码中2进制内容对应的整数是13.
               换行符:在ASC编码中2进制内容对应的整数是10.
            */
            //此处设置两个变量来判断结束
            char pre='a',cur='a'; //pre上一次读取字符,cur本次读取的字符
            while (((d = in.read())!=-1)) {
                    cur = (char)d; //将本地读取的字节转换为字符赋值给cur
                    if(pre==13&cur==10){ //是否连续读取到回车+换行
                        break;
                    }
                    builder.append(cur); //将本次读取的字符拼接到StringBuilder中
                    pre=cur; //在进行下一个字符读取前将本地读取的字符记录为上次读取的字符
                }
             String line = builder.toString().trim(); 
                //此时尾部会有一个多余的回车符,所以使用trim()去除
             System.out.println(line); //GET /index.html HTTP/1.1

            //请求行的相关信息
            String method; //请求方式
            String uri; //抽象路径
            String protocol; //版本协议
            String[] data = line.split("\\s"); //以空格分隔
            method = data[0];
            uri = data[1];
            protocol = data[2];
            System.out.println("method:"+method); //method:GET
            System.out.println("uri:"+uri); //uri:/index.html
            System.out.println("protocol:"+protocol); //protocol:HTTP/1.1
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

}

测试
启动服务端,在浏览器中输入http://localhost:8088/index.html
输出结果为:
在这里插入图片描述
接下来继续解析请求,上一步完成了解析请求行的操作,继续使用该操作完成解析消息头

实现:
1:在ClientHandler中定义方法:readLine,用于将读取一行字符串的操作重用
2:将解析请求行中读取第一行内容的操作改为调用readLine
3:继续利用readLine读取消息头并保存每个消息头

在这里插入图片描述

由于消息头信息不止一行,所以会存在多次读一行的操作,因此在run()方法下定义一个方法,将读取一行字符串的代码剪切进去,实现代码复用。(注意:复用的代码一般都不会自己处理异常)

private String readLine() throws IOException {
            InputStream in = socket.getInputStream();
            StringBuilder builder = new StringBuilder();
            int d;
            /*
               请求行是一行字符串,以连续的两个字符(回车符和换行符)作为结束这一行的标志。
               消息头是多行字符串,以连续的两个字符(回车符和换行符)作为结束每一行的标志。
               回车符:在ASC编码中2进制内容对应的整数是13.
               换行符:在ASC编码中2进制内容对应的整数是10.
            */
            char pre='a',cur='a'; //pre上一次读取字符,cur本次读取的字符
            while (((d = in.read())!=-1)) {
                cur = (char)d; //将本地读取的字节转换为字符赋值给cur
                if(pre==13&cur==10){ //是否连续读取到回车+换行
                    break;
                }
                builder.append(cur); 
                pre=cur; //在进行下一个字符读取前将本地读取的字符记录为上次读取的字符
            }
            return builder.toString().trim(); 
            //此时尾部会有一个多余的回车符,所以使用trim()去除
        }

run()方法的代码为:(采用Map保存消息头)

 try {
            //1解析请求
            //1.1解析请求行
            String line = readLine();
            System.out.println("请求行:"+line); //GET /index.html HTTP/1.1

            //请求行的相关信息
            String method; //请求方式
            String uri; //抽象路径
            String protocol; //协议
            String[] data = line.split("\\s");
            method = data[0];
            uri = data[1];
            protocol = data[2];
            System.out.println("method:"+method); //method:GET
            System.out.println("uri:"+uri); //uri:/index.html
            System.out.println("protocol:"+protocol); //protocol:HTTP/1.1

            //1.2解析消息头
            //消息头相关信息保存
            Map<String,String> headers = new HashMap<>();
            while (true){
                line = readLine();
                if (line.isEmpty()){ //若读取的字符串为空串,说明读取到了回车+换行
                    break;
                }
                System.out.println("消息头:"+line);
                //将消息头的名字和值以key,value形式存入headers这个Map中
                data = line.split(":\\s");
                headers.put(data[0],data[1]);
            }
            System.out.println("headers:"+headers);

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

为了后期维护,将功能拆分,实现高内聚低耦合:

由于ClientHandler主要用于控制流程,因此将ClientHandler中第一个环节解析请求的细节拆分出去,使得ClientHandler仅关心处理一次HTTP交互的流程控制.

实现:
1:新建一个包:com.webserver.http
2:在http包下新建类:HttpServletRequest 请求对象

  • 使用这个类的每一个实例表示客户端发送过来的一个HTTP请求

3:在HttpServletRequest的构造方法中完成解析请求的工作

  • 实际就是将ClientHandler中的部分代码挪到HttpServletRequest中
  • 并将请求方式等局部变量改为私有实例变量,方便实例化后调用 (记得设置get()方法,这里因为是获取请求信息,所以用不到set())
  • 为了代码直接清晰,将解析细节代码提取成方法

4:ClientHandler第一步解析请求只需要实例化一个HttpServletRequest即可.

package com.webserver.http;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 请求对象
 * 该类的每一个实例用于表示HTTP协议规定的客户端发送过来的一个请求内容。
 * 每个请求由三部分构成:
 * 请求行,消息头,消息正文
 */
public class HttpServletRequest {
    //请求行的相关信息
    private String method; //请求方式
    private String uri; //抽象路径
    private String protocol; //协议
    //消息头相关信息
    private Map<String,String> headers = new HashMap<>();

    private Socket socket;
    /**
     * 实例化请求对象的过程也是解析的过程
     */
    public HttpServletRequest(Socket socket) throws IOException {
        this.socket = socket;
        //1.1解析请求行
        parseRequestLine();
        //1.2解析消息头
        parseHeaders();
        //1.3解析消息正文
        parseContent();

    }

    /**
     * 解析请求行
     */
    private void parseRequestLine() throws IOException {
        String line = readLine();
        System.out.println("请求行:"+line); //GET /index.html HTTP/1.1

        //将请求行内容拆分出来并分别赋值给三个变量
        String[] data = line.split("\\s");
        method = data[0];
        uri = data[1];
        protocol = data[2];
        System.out.println("method:"+method); //method:GET
        System.out.println("uri:"+uri); //uri:/index.html
        System.out.println("protocol:"+protocol); //protocol:HTTP/1.1
    }

    /**
     * 解析消息头
     */
    private void parseHeaders() throws IOException {
        while (true){
            String line = readLine();
            if (line.isEmpty()){ //若读取的字符串为空串,说明读取到了回车+换行
                break;
            }
            System.out.println("消息头:"+line);
            //将消息头的名字和值以key,value形式存入headers这个Map中
            String[] data = line.split(":\\s");
            headers.put(data[0],data[1]);
        }
        System.out.println("headers:"+headers);
    }

    /**
     * 解析消息正文
     */
    private void parseContent(){} //此时还没有消息正文,所以暂不进行操作

    /**
     * 按行读取数据
     * @return String
     * @throws IOException
     */
    private String readLine() throws IOException {
        //由于在接收到的数据不会完全是文本数据,所以此处不应该设置为字符流。
        //又字符流存在缓冲区,不适合一行一行读取的情况,可能会丢失数据。
        InputStream in = socket.getInputStream();
        //由于String的连接性能差,所以此处采用StringBuilder/StringBuffer
        //但因为这里不会出现并发安全问题,所以选用StringBuilder
        StringBuilder builder = new StringBuilder();
        int d;
            /*
               请求行是一行字符串,以连续的两个字符(回车符和换行符)作为结束这一行的标志。
               消息头是多行字符串,以连续的两个字符(回车符和换行符)作为结束每一行的标志。
               回车符:在ASC编码中2进制内容对应的整数是13.
               换行符:在ASC编码中2进制内容对应的整数是10.
            */
        //此处设置两个变量来判断结束
        char pre='a',cur='a'; //pre上一次读取字符,cur本次读取的字符
        while (((d = in.read())!=-1)) {
            cur = (char)d; //将本地读取的字节转换为字符赋值给cur
            if(pre==13&cur==10){ //是否连续读取到回车+换行
                break;
            }
            builder.append(cur); //将本次读取的字符拼接到StringBuilder中
            pre=cur; //在进行下一个字符读取前将本地读取的字符记录为上次读取的字符
        }
        return builder.toString().trim(); 
        //此时尾部会有一个多余的回车符,所以使用trim()去除,并返回一个字符串
    }

    public String getMethod() {
        return method;
    }

    public String getUri() {
        return uri;
    }

    public String getProtocol() {
        return protocol;
    }
    
    //由于直接return集合会存在安全隐患,所以此处不建议直接生成

    /**
     * 根据给定的消息头的名字(键)获取对应的值
     * @param name
     * @return 键对应的值
     */
    public String getHeader(String name){
        return headers.get(name); 
    }
}

ClientHandler修改为:

/**
 * 该线程任务负责与指定的客户端完成HTTP交互
 * 每次HTTP交互都采取一问一答的规则,因此交互由三步来完成:
 * 1:解析请求
 * 2:处理请求
 * 3:发送响应
 */
public class ClientHandler implements Runnable{ //客户端处理器
    private Socket socket;

    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //1解析请求
            HttpServletRequest request = new HttpServletRequest(socket);

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

        }



}

上述操作如图所示:
在这里插入图片描述

完成响应客户端的工作

这里先将ClientHandler中处理一次交互的第三步:响应客户端 实现出来。
目标:将一个固定的html页面通过发送一个标准的HTTP响应回复给浏览器使其呈现出来。
需要的知识点:
1:HTML基础语法,html是超文本标记语言,用于构成一个"网页"的语言。
2:HTTP的响应格式。

实现:
一:先创建第一个页面index.html
1:在src/main/resources下新建目录static
这个目录用于存放当前服务端下所有的网络应用中的静态资源。
注:每个网路应用相当于一个"网站"的所有内容,而每个网络应用以一个独立的目录保存在static下,该目录的名字就是这个网络应用的名字。
2:在static目录下新建目录:myweb,作为我们的第一个"网站"
3:在myweb目录下新建第一个页面:index.html
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
二:实现将index.html页面响应给浏览器
在ClientHandler第三步发送响应处,按照HTTP协议规定的响应格式,将该页面包含在正文部分将其发送给浏览器即可。

注意:非java文件会存放到resources中!

操作2:将index.html页面响应给浏览器,将resource目录中static/myweb/index.html响应给浏览器

在这里插入图片描述
在这里插入图片描述
HTTP发送响应:
在这里插入图片描述

发送状态行:
在这里插入图片描述
在ClientHandler中:

OutputStream out = socket.getOutputStream();
//3.1发送状态行
String line = "HTTP/1.1 200 OK";
byte[] data = line.getBytes(StandardCharsets.ISO_8859_1);
//注意:此处的标准字符集ISO_8859_1
//虽然ISO_8859_1和UTF_8中对英文的Unicode值都是一样的
//但是要符合标准,还是选择使用ISO_8859_1
out.write(data);
out.write(13);//发送回车符
out.write(10);//发送换行符

注意:这里的响应正文为index.html

由于index.html的原路径在V6/src/main/resources/static/myweb/index.html,此时如果只是指定一个相对路径,可能会出现找不到文件的错误;但若是指定为绝对路径,不利于后期维护。
在这里插入图片描述
因为每个maven项目编译后都会将src/main/java目录和src/main/resources目录,最终合并到target/classes中,所以每个maven项目都会有一个target/classes。这样就解决了换maven项目后,文件路径出错的问题。

实际开发中,我们常用的相对路径都是类的加载路径。对应的写法:
类名.class.getClassLoader().getResource("./")
这里的"./"当前目录指的就是类加载路径的开始目录。它的实际位置JVM理解的就是当前类的包名指定中最上级包的上一层。
例如下面的代码中,当前类ClientHandler指定的包:
package com.webserver.core;
那么包的最上级就是com,因此类加载路径的开始目录就是com的上级目录
实际就是项目的target/classes这个目录了。

在这里插入图片描述
所以文件路径设定为:

File file = new File(
                    ClientHandler.class.getClassLoader().getResource(
                            "./static/myweb/index.html"
                    ).toURI()
            );

发送响应头:
在这里插入图片描述

//3.2发送响应头
line = "Content-Type: text/html";
data = line.getBytes(StandardCharsets.ISO_8859_1);
out.write(data);
out.write(13);//发送回车符
out.write(10);//发送换行符

line = "Content-Length: "+file.length();
data = line.getBytes(StandardCharsets.ISO_8859_1);
out.write(data);
out.write(13);//发送回车符
out.write(10);//发送换行符
//单独发送回车+换行表示响应头部分发送完毕
out.write(13);//发送回车符
out.write(10);//发送换行符

发送响应正文:
在这里插入图片描述

//3.3发送响应正文
byte[] buf = new byte[1024*10];
int len;
FileInputStream fis = new FileInputStream(file);
while((len = fis.read(buf))!=-1){
	out.write(buf,0,len);
}

响应的完整代码:

package com.webserver.core;

import com.webserver.http.HttpServletRequest;
import java.io.*;
import java.net.Socket;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 该线程任务负责与指定的客户端完成HTTP交互
 * 每次HTTP交互都采取一问一答的规则,因此交互由三步来完成:
 * 1:解析请求
 * 2:处理请求
 * 3:发送响应
 */
public class ClientHandler implements Runnable{
    private Socket socket;
    public ClientHandler(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //1解析请求
            HttpServletRequest request = new HttpServletRequest(socket);

            //3发送响应
            File file = new File(
                    ClientHandler.class.getClassLoader().getResource(
                            "./static/myweb/index.html"
                    ).toURI()
            );
           
            OutputStream out = socket.getOutputStream();
            //3.1发送状态行
            String line = "HTTP/1.1 200 OK";
            byte[] data = line.getBytes(StandardCharsets.ISO_8859_1);
            out.write(data);
            out.write(13);//发送回车符
            out.write(10);//发送换行符

            //3.2发送响应头
            line = "Content-Type: text/html";
            data = line.getBytes(StandardCharsets.ISO_8859_1);
            out.write(data);
            out.write(13);//发送回车符
            out.write(10);//发送换行符

            line = "Content-Length: "+file.length();
            data = line.getBytes(StandardCharsets.ISO_8859_1);
            out.write(data);
            out.write(13);//发送回车符
            out.write(10);//发送换行符
            //单独发送回车+换行表示响应头部分发送完毕
            out.write(13);//发送回车符
            out.write(10);//发送换行符

            //3.3发送响应正文
            byte[] buf = new byte[1024*10];
            int len;
            FileInputStream fis = new FileInputStream(file);
            while((len = fis.read(buf))!=-1){
                out.write(buf,0,len);
            }

        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        } finally{
            //一次HTTP交互后断开链接(HTTP协议要求)
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

启动服务端后,在浏览器中输入 http://localhost:8088/,显示效果如下:
在这里插入图片描述
2处理请求:

由于未来文件路径还是可能会有变化
在这里插入图片描述
所以文件路径响应正文时的文件内容路径也不应该固定。此时可以发现这个路径可以通过之前在HttpServletRequest中获取的抽象路径来进行一些调整。在这里插入图片描述在ClientHandler中:

//2处理请求
//例如:浏览器地址栏输入的路径为:http://localhost:8088/myweb/index.html
//那么解析请求后得到的抽象路径部分uri:/myweb/index.html
String path = request.getUri();
File file = new File(
       ClientHandler.class.getClassLoader().getResource(
           "./static" + path
       ).toURI()
);

测试:
http://localhost:8088/myweb/index.html
http://localhost:8088/myweb/classTable.html

注意:进行上述修改前,在浏览器中输入这两个测试值,它返回的都是http://localhost:8088/myweb/index.html页面所展示的内容。修改过后则用户输入哪个地址就调用哪个。
在这里插入图片描述
在这里插入图片描述

存在代码冗余,进行调整,实现代码复用:

在run()方法下定义一个方法:

private void println(String line) throws IOException {
            OutputStream out = socket.getOutputStream();
            byte[] data = line.getBytes(StandardCharsets.ISO_8859_1);
            out.write(data);
            out.write(13);//发送回车符
            out.write(10);//发送换行符
        }

run()中修改为:

public void run() {
        try {
            //1解析请求
            HttpServerRequest request = new HttpServerRequest(socket);

            //2处理请求
            String path = request.getUri();
            System.out.println("抽象路径:"+path);

            //3发送响应
            File file = new File(
                    ClientHandler.class.getClassLoader().getResource(
                            "./static" + path
                    ).toURI()
            );
            
            //3.1发送状态行
            String line = "HTTP/1.1 200 OK";
            println(line);

            //3.2发送响应头
            line = "Content-Type: text/html";
            println(line);

            line = "Content-Length: "+file.length();
            println(line);
            //单独发送回车+换行表示响应头部分发送完毕
            println("");

            //3.3发送响应正文
            OutputStream out = socket.getOutputStream();
            byte[] buf = new byte[1024*10];
            int len;
            FileInputStream fis = new FileInputStream(file);
            while((len = fis.read(buf))!=-1){
                out.write(buf,0,len);
            }

            System.out.println("响应发送完毕!");
            } catch (IOException | URISyntaxException e) {
                e.printStackTrace();
            }finally {
                 //一次HTTP交互后断开链接(HTTP协议要求)
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

       }

在这里插入图片描述

注意

在这里会因为在浏览器中输入路径出错,而报FileNotFoundException错误
例如输入http://localhost:8088/
原因在于
在这里插入图片描述

所以需要设置一个遇到错误时的响应

->->->->转到WebServer【笔记2】

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JSP(Java Server Pages)是一种动态网页技术,它可以将Java代码嵌入到HTML页面中,实现动态页面的生成。JSP技术在Web开发中使用非常广泛,下面将介绍JSPWeb开发的基础知识。 一、JSP基础语法 JSP页面的基本语法是HTML语法,但是在HTML页面中可以嵌入Java代码。JSP页面中使用<% %>标签来包含Java代码,使用<%= %>标签来输出Java代码生成的结果。例如: ``` <html> <head> <title>JSP页面</title> </head> <body> <% String message = "Hello, JSP!"; out.println(message); %> </body> </html> ``` 在上面的例子中,我们定义了一个message变量,并且使用out.println()方法将其输出到页面上。 二、JSP内置对象 JSP页面中有一些内置对象,这些对象可以帮助我们快速开发Web应用程序。常用的JSP内置对象包括: 1. request对象:代表HTTP请求,可以获取请求参数和请求头等信息。 2. response对象:代表HTTP响应,可以设置响应头和响应体等信息。 3. session对象:代表用户会话,可以存储用户信息和状态等。 4. application对象:代表Web应用程序,可以获取应用程序级别的信息和状态等。 5. pageContext对象:代表JSP页面上下文,可以获取页面级别的信息和状态等。 6. out对象:代表JSP页面的输出流,可以将数据输出到页面上。 三、JSP标签库 JSP标签库是一组自定义标签,用于实现复杂的业务逻辑和页面效果。JSP标签库通常通过标签文件或Java类的形式来实现。在JSP页面中,我们可以使用标签库来实现模板化的页面设计,例如: ``` <%@ taglib prefix="my" uri="http://www.example.com/mytags" %> <html> <head> <title>JSP页面</title> </head> <body> <my:hello name="JSP" /> </body> </html> ``` 在上面的例子中,我们使用my:hello标签来输出“Hello, JSP!”这个字符串。 四、JSP中的EL表达式 EL(Expression Language)表达式是一种简化的表达式语言,用于获取和操作页面中的数据。EL表达式通常使用${ }标签来包含,例如: ``` <html> <head> <title>JSP页面</title> </head> <body> ${1+1} </body> </html> ``` 在上面的例子中,我们使用EL表达式输出了2这个结果。 五、JSP中的MVC架构 MVC(Model-View-Controller)是一种软件架构模式,用于将应用程序分为三个部分:模型、视图和控制器。在JSPWeb开发中,通常会使用MVC架构来实现应用程序的开发。例如: 1. 模型:使用JavaBean来表示业务逻辑和数据操作。 2. 视图:使用JSP页面来表示用户界面和页面效果。 3. 控制器:使用Servlet来实现请求的转发和业务逻辑的控制。 在MVC架构中,模型、视图和控制器之间通过请求和响应来进行交互,这样可以将应用程序分离为三个独立的部分,便于开发和维护。 总之,JSPWeb开发是一种非常重要的技能,它可以帮助我们快速搭建Web应用程序,并且可以大大提高应用程序的开发效率和质量。希望这些信息对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值