Servlet基础知识

Servlet基础知识,第1张

Servlet基础知识二
  • 1.Servlet运行原理
    • 1.1 Tomcat详解
    • 1.2Tomcat执行流程
  • 2.Servlet API详解
    • 2.1 HttpServlet
      • 2.1.1 核心方法
      • 2.2.2 代码示例:处理GET请求
      • 2.2.3代码示例:处理POST请求
    • 2.2 HttpServletRequest
      • 2.2.1核心方法
      • 2.2.2打印Hreader信息
      • 2.2.3获取GET请求中的参数
      • 2.2.4 获取POST请求中的参数(1)
      • 2.2.5 获取JSON格式参数
      • 2.2.6获取JSON格式参数(2)
      • 2.2.7 使用 postman模拟发送请求
  • 3.HttpServletResponse
      • 设置状态码
      • 自动刷新
      • 重定向

1.Servlet运行原理

在Servlet的代码中我们并没有写main方法,那么代码中的doGet代码部分是如何被调用的,这和Tomcat有关。

1.1 Tomcat详解

我们代码的实现是在Tomcat基础上运行的。

当浏览器给服务器发送请求的时候,Tomcat作为HTTP服务器,就可以接收到这个请求。
HTTP协议作为一个应用层协议,需要底层协议栈来支持工作:

详细的交互过程:

1.接收请求
(1)用户在浏览器输入一个URL,此时浏览器就会构成一个HTTP请求。
(2)这个HTTP请求会经过网络协议栈逐层封装成二进制比特流,最终通过物理层的硬件设备转换成光电信号/电信号传输出去。
(3)这些承载信息的光信号/电信号通过互联网上的一系列网络设备,最终达到目标主机。
(4)服务器主机收到这些光信号/电信号,又会通过网络协议栈逐层进行分用,层层解析,最终还原HTTP请求,并交给Tomcat进程进行处理(根虎端口号确定进程)。
(5)Tomcat通过Socket读取到这个请求(一个字符串),并按照HTTP请求的格式来解析这个请求,根据请求中的Context Path确定一个webapp,再通过Servlet Path确定一个具体的类,再根据当前请求的方法(GET/POST/…),决定调用这个类的doGet或者doPost等方法,我们的代码中的doGet/doPost方法的第一个参数HttpServletRequest就包含了这个HTTP请求的详细信息。
2.根据请求计算响应
在我们的doGet/doPost方法中,就执行到了我们自己的代码,我们自己的代码会根据请求中的一些信息,来给HttpServletResponse对象设置一些属性,例如状态码,header,body等。
3.返回响应
(1)doGet/doPost执行完毕后,Tomcat就会自动把HttpsServletResponse这个我们刚设置好的对象转换成一个符合HTTP协议的字符串,通过Socket把这个响应发送出去。
(2)此时响应数据在服务器的主机上通过网络协议栈层层封装,最终又得到一个二进制的bit流,通过物理层硬件设备转换成光信号/电信号传输出去。
(3)这些承载信息的光信号/电信号通过互联网上的一系列网络设备,最终到达浏览器所在的主机(需要网络层和数据链路层参与)。
(4)浏览器主机收到这些光信号/电信号,又会通过网络协议栈逐层进行分用,层层解析,最终还原成HTTP响应,并交给浏览器处理。
(5)浏览器也通过Socket读到这个响应(一个字符串),按照HTTP响应的格式来解析这这个响应,并且把body中的数据按照一定的格式显示在浏览器的界面上。

1.2Tomcat执行流程

通过代码形式描述Tomcat初始化/处理请求两部分核心逻辑。
1.Tomcat初始化流程

class Tomcat {
    // ⽤来存储所有的 Servlet 对象
    private List<Servlet> instanceList = new ArrayList<>();
    
    public static void main(String[] args) {
        new Tomcat().start();
   }
    public void start() {
           // 根据约定,读取 WEB-INF/web.xml 配置⽂件;
        // 并解析被 @WebServlet 注解修饰的类
        // 假定这个数组⾥就包含了我们解析到的所有被 @WebServlet 注解修饰的类.
        Class<Servlet>[] allServletClasses = ...;
        // 这⾥要做的的是实例化出所有的 Servlet 对象出来;
        for (Class<Servlet> cls : allServletClasses) {
            // 这⾥是利⽤ java 中的反射特性做的
               // 实际上还得涉及⼀个类的加载问题,因为我们的类字节码⽂件,是按照约定 的
            // ⽅式(全部在 WEB-INF/classes ⽂件夹下)存放的,所以 tomcat 内部是
            // 实现了⼀个⾃定义的类加载器(ClassLoader)⽤来负责这部分⼯作。
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
       }
        // 调⽤每个 Servlet 对象的 init() ⽅法,这个⽅法在对象的⽣命中只会被调⽤这 ⼀次;
        for (Servlet ins : instanceList) {
            ins.init();
       }
        // 利⽤我们之前学过的知识,启动⼀个 HTTP 服务器
        // 并⽤线程池的⽅式分别处理每⼀个 Request
        ServerSocket serverSocket = new ServerSocket(8080);
        // 实际上 tomcat 不是⽤的固定线程池,这⾥只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是⽤⼀个线程独⽴⽀持,这⾥体现了我们 Servlet 是运⾏在多线 程环境下的
            pool.execute(new Runnable() {
               doHttpRequest(socket);
                   });
       }
        // 调⽤每个 Servlet 对象的 destroy() ⽅法,这个⽅法在对象的⽣命中只会被调
⽤这⼀次;
        for (Servlet ins : instanceList) {
            ins.destroy();
       }
   }
}

(1)Tomcat的代码中内置了main方法,当我们启动Tomcat的时候,就是从Tomcat的main方法开始执行的。
(2)被@WebServlet注解修饰的类会在Tomcat启动的时候就被获取到,并集中管理。
(3)Tomcat通过反射的语法机制来创建被@WebServlet注解修饰的类的实例。
(4)这些实例被创建完了之后,会调用其中的init方法进行初始化(这个方法是HttpServlet是自带的,我们自己写的类可以重写init).
(5)这些实例被销毁之前,会调用其中的destory方法进行收尾(这个方法是HttpServlet自带的,我们自己写的类可以重写destory)
(6)Tomcat内部也是通过Socket API进行网络通信。
(7)Tomcat为了能同时响应多个HTTP请求,采取了多线程的方式实现,因此Servlet是运行在多线程环境下的
2.Tomcat处理请求流程

class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进⾏ HTTP 协议的请求解析,和响
应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        // 判断 URL 对应的⽂件是否可以直接在我们的根路径上找到对应的⽂件,如果找到, 就是静态内容
        // 直接使⽤我们学习过的 IO 进⾏内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
       }
        // ⾛到这⾥的逻辑都是动态内容了
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        // 调⽤ Servlet 对象的 service ⽅法
        // 这⾥就会最终调⽤到我们⾃⼰写的 HttpServlet 的⼦类⾥的⽅法了
        try {
            ins.service(req, resp);    
       } catch (Exception e) {
            // 返回 500 ⻚⾯,表示服务器内部错误
       }
   }
}

(1)Tomcat从Socket中读到的HTTP请求是一个字符串,然后会按照HTTP协议的格式解析成一个HttpServlet对象。
(2)Tomcat会根据URL中的path判定这个请求是请求一个静态资源还是动态资源,如果是静态资源,如果是静态资源,直接找到对应的文件把文件的内容通过Socket返回,如果是动态资源,才会执行到Servlet的相关逻辑。
(3)Tomcat会根据URL中的Context PathServlet Path确定要调用哪个Servlet 实例的service方法。
(4)通过service方法,就会进一步调用到自己写的doGet或者doPost.
3.Servlet的service方法实现

(1)Servlet的service方法内部会根据当前请求的方法,决定调用其中的某个doXXX方法。
(2)在调用doXXX方法的时候,就会触发多态机制,从而执行到我们自己写的子类中的doXXX方法。

多态:
(1)我们前⾯⾃⼰写的 HelloServlet 类, 继承⾃ HttpServlet 类. ⽽ HttpServlet ⼜继承⾃ Servlet. 相当于 HelloServlet 就是 Servlet 的⼦类. 接下来, 在 Tomcat 启动阶段, Tomcat 已经根据注解的描述, 创建了 HelloServlet 的实例, 然后把这个实 例放到了 Servlet 数组中.
(2) 后⾯我们根据请求的 URL 从数组中获取到了该 HelloServlet 实例, 但是我们是通过 Servlet ins 这 样的⽗类引⽤来获取到 HelloServlet 实例的.
(3) 最后, 我们通过 ins.doGet() 这样的代码调⽤ doGet 的时候, 正是 “父类引用指向⼦类对象”, 此时就 会触发多态机制, 从⽽调⽤到我们之前在 HelloServlet 中所实现的 doGet ⽅法
等价的代码:
Servlet ins = new HelloServlet(); ins.doGet(req, resp);

2.Servlet API详解 2.1 HttpServlet

在写servlet代码的时候,首先第一步就是先创建类,继承HttpServlet,并重写其中的某些方法。

2.1.1 核心方法


1.在实际中我们主要写doXXX方法,很少会重写init/destory/service.
2.这些方法的调用时机,就称为"Servlet生命周期":


HttpServlet的实例只是在程序启动时创建一次,而不是每次收到HTTP请求都重新创建实例。

2.2.2 代码示例:处理GET请求

1.创建MethodServlet.java,创建doGet方法:

2.创建testMethod.html,放到webapp目录中,如下:

一个Servlet程序中可以同时部署静态文件,静态文件就放到webapp目录中即可。

3.数据提交的两种方式:
(1)form表单提交:


login.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录系统</title>
</head>
<body>
<form action="login" method="post">
    <div style="margin-top:50px;margin-left:40%">
        <h1 style="padding-left:50px">用户登录</h1>
        姓名:<input type="text" name="username">
        <p>
        密码:<input type="password" name="password">
        <p>
        <div style="padding-left:50px">
          <input type="submit" value="提 交">&nbsp;&nbsp;&nbsp;&nbsp;
          <input type="reset" value="重 置">
        </div>
    </div>
</form>
</body>
</html>

LoginServlet.java:

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("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String result = "未知错误";
        // 1.得到参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2.业务处理
        // 非空效验
        if (null != username && null != password &&
                !username.equals("") && !password.equals("")) {
            if (username.equals("admin") && password.equals("admin")) {
                result = "恭喜:登录成功!";
            } else {
                result = "登录失败,用户名或密码输入错误,请检查!";
            }
        } else {
            result = "非法参数!";
        }

        resp.setContentType("text/html; charset=utf-8");

        // 3.将结果返回给前端
        resp.getWriter().write(result);
    }
}


输入正确的用户名和密码:


输入错误的用户名和密码:


(2)ajax提交
Ajax 即 Asynchronous Javascript And XML(异步JavaScript和XML),使用Ajax 不需要刷新整个页面,这使得程序能够更快地回应⽤户的 *** 作。

login-ajax.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录系统</title>
    <script src="js/jquery-1.9.1.min.js"></script>
</head>
<body>
    <div style="margin-top:50px;margin-left:40%">
        <h1 style="padding-left:50px">用户登录</h1>
        姓名:<input id="username" type="text" name="username">
        <p>
            密码:<input id="password" type="password" name="password">
        <p>
        <div style="padding-left:50px">
            <input  type="button" value="提 交" onclick="mySubmit()">&nbsp;&nbsp;&nbsp;&nbsp;
            <input type="reset" value="重 置">
        </div>
    </div>
<script>
     function mySubmit(){
      <!-- 非空效验  -->
      var username=jQuery("#username");
      var password=jQuery("#password");
      if("" == username.val()){
           alert("请先输入用户名!")
           return;
      }
      if(""==password.val()){
            alert("请先输入密码!");
            return;
      }
         jQuery.ajax({
             url:"login",
             type:"POST",
             data:{"username":username.val(),"password":password.val()},
             success:function(data){
             alert(data);
             }
         });
     }
</script>
</body>
</html>




关于乱码问题:
如果我们在响应代码中写入中文,例如:

resp.getWriter().write("GET 响应");


此时在浏览器访问的时候,就会看到乱码现象:

我们可以在代码中,通过resp.setContentType("text/html;charset=utf-8");显式的指定编码方式。

2.2.3代码示例:处理POST请求

在 MethodServlet.java 中, 新增 doPost ⽅法.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
    resp.setContentType("text/html; charset=utf-8");
    resp.getWriter().write("POST 响应");
}

在 testMethod.html 中, 新增⼀个按钮, 和对应的点击事件处理函数:

<!doctype html>
<html lang="en"> <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="js/jquery-1.9.1.min.js"></script>
</head> <body> <button type="submit" onclick="sendGet()">发送 GET 请求</button> <br> <button onclick="sendPost()">发送 POST 请求</button> <script>
    function sendGet() {
        jQuery.ajax({
            url: "method",
            type: "GET",
            // data: {"name": "Java"},
            // contentType:"application/json", // 请求参数类型
            // dataType: "json", // 响应类型
            success: function (data) {
                console.log(data)
           }
       });
   }
    function sendPost() {
        jQuery.ajax({
            url: "method",
            type: "POST",
            // data: {"name": "Java"},
            // contentType:"application/json", // 请求参数类型
            // dataType: "json", // 响应类型
            success: function (data) {
                console.log(data)
           }
       });
   }
</script>
</body>
</html>
2.2 HttpServletRequest 2.2.1核心方法


通过这些方法可以获取到一个请求中的各个方面的信息。
请求对象是服务器收到的内容,不应该修改,因此上面的方法也都只是读方法而不是写方法。

MyReqServlet.java:

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("/myreq")
public class MyReqServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        StringBuilder builder = new StringBuilder();
        // 得到请求的协议和版本号
        builder.append("协议:" + req.getProtocol() + "
"
); // 得到请求的类型 builder.append("Method:" + req.getMethod() + "
"
); // 得到 uri builder.append("URI:" + req.getRequestURI() + "
"
); builder.append("URL:" + req.getRequestURL() + "
"
); builder.append("ContextPath:" + req.getContextPath() + "
"
); builder.append("QueryString:" + req.getQueryString() + "
"
); builder.append("
请求头"
); // 得到所有的请求类型(headerNames)和请求值 Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { // 判断还有没有 head name String headName = headerNames.nextElement(); // 得到 head value String headValue = req.getHeader(headName); builder.append(headName + ": " + headValue + "
"
); } builder.append("
"
); builder.append("参数:" + req.getParameter("name") + "
"
); resp.getWriter().write(builder.toString()); } }



使用Postman软件查看body:

2.2.2打印Hreader信息

创建ShowRequest类:

@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse
resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf-8");
        StringBuilder respBody = new StringBuilder();
        respBody.append(req.getProtocol());
        respBody.append("
"
); respBody.append(req.getMethod()); respBody.append("
"
); respBody.append(req.getRequestURI()); respBody.append("
"
); respBody.append(req.getContextPath()); respBody.append("
"
); respBody.append(req.getQueryString()); respBody.append("
"
); respBody.append("headers:"); Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); respBody.append(headerName + " "); respBody.append(req.getHeader(headerName)); respBody.append("
"
); } resp.getWriter().write(respBody.toString()); } }

运行程序,在浏览器输入url地址,可以看到:

2.2.3获取GET请求中的参数

GET请求中的参数一般都是通过query string传递给服务器的,形如:

http://localhost:8080/first-servlet/postjson/student?userId=1111&classId=100

此时在浏览器通过query string给服务器传递了两个参数,userId和classid值分别为"userId"和"classid"在服务器端就可以通过getParameter来获取参数的值。
创建GetParameter类:

重新部署程序,在浏览器通过http://127.0.0.1:8080/ServletHelloWorld/getParameter访问,可以看到

当没有query string的时候,getParameter获取的值null,如果通过http://127.0.0.1:8080/ServletHelloWorld/getParameter?userId=123&classId=456 访问, 可以看到:

此时说明服务器以及获取到客户端传递过来的参数。

getParameter的返回值类型为String,必要时需要手动把String转成int.

2.2.4 获取POST请求中的参数(1)

使用postman查看GET请求中的参数:

POST 请求的参数⼀般通过 body 传递给服务器. body 中的数据格式有很多种. 如果是采⽤ form 表单的形 式, 仍然可以通过 getParameter 获取参数的值:
创建类JsonPostServlet.java:

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("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回的类型和编码
        resp.setContentType("text/html;charset=utf-8");
        String username=req.getParameter("username");
        String password=req.getParameter("password");
        resp.getWriter().write("username"+username+","+"password"+password);
    }
}

testJson.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="postParameter" method="POST">
    <input type="text" name="userId">
    <input type="text" name="classId">
    <input type="submit" value="提交">
</form>
</body>
</html>


使用postman查看:

2.2.5 获取JSON格式参数

使⽤之前 getParameter 的⽅式是获取不了 JSON 格式的数据的。

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("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置返回的类型和编码
        resp.setContentType("text/html;charset=utf-8");
        String username=req.getParameter("username");
        String password=req.getParameter("password");
        resp.getWriter().write("username"+username+","+"password"+password);
    }
}


body中带有JSON格式的数据,方法使⽤之前 getParameter不能获取到:

使用InputStream获取JSON参数:

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置返回类型和编码
        resp.setContentType("text/html; charset=utf-8");
        int length=req.getContentLength();

        // 1.得到数据流
        ServletInputStream inputStream = req.getInputStream();
        // 2.使用数组接收流信息
        byte[] bytes = new byte[length];
        inputStream.read(bytes);
        // 3.将数组转换成字符串(或对象)
        String result = new String(bytes, "utf-8");
        resp.getWriter().println(result);

    }
}

注意: 到⽬前为⽌, 服务器拿到的 JSON 数据仍然是⼀个整体的 String 类型, 如果要想获取到 userId 和 classId 的具体值, 还需要搭配 JSON 库进⼀步解析.

2.2.6获取JSON格式参数(2)

java JSON对象 *** 作:
1.阿里巴巴 fast json/fast json2
2.阿帕奇 jackson
(a)将对象转换成JSON字符串。
(b)将JSON字符串转换成对象。

引入Jackson这个库,进行JSON解析:
1.在中央仓库搜索Jackson,选择Jackson Databind:
(1)



把中央仓库中的依赖配置添加到 pom.xml 中:

(2)在项目为了避免写太多的getter和setter方法,有一种更简便的写法。
首先在pom.xml配置lombok:


把lombok依赖复制到pom.xml中:


可以更加简便的使用get和set方法:

安装lombok插件:


使用代码实现json字符串和对象之间的转换:
a.将json对象转换成字符串:

b.将字符串转化为对象:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.ToString;

public class App {
    public static void main(String[] args) throws JsonProcessingException {
        //1.创建一个json对象
        ObjectMapper objectMapper=new ObjectMapper();
//        //2.1将对象转换成json字符串
//        Student student=new Student();
//        student.setId(1);
//        student.setName("zhangsan");
//        student.setPassword("123");
//        String result=objectMapper.writeValueAsString(student);
//        System.out.println(result);
        //------------2.2将json字符串转换为对象---
        String jsonStr="{\"id\":1,\"name\":\"zhangsan\",\"password\":\"123\"}";
        Student zhangsan=objectMapper.readValue(jsonStr,Student.class);
        System.out.println(zhangsan);
    }
@Data
static class Student{
        private int id;
        private String  name;
        private  String password;
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
}


(3)实现获取JSON格式的代码:
JSON后端读取代码:

JsonPostServlet.java:

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
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.HashMap;


@WebServlet("/postjson")
public class JsonPostServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 设置返回类型和编码
        resp.setContentType("text/html; charset=utf-8");
        int length=req.getContentLength();

        // 1.得到数据流
        ServletInputStream inputStream = req.getInputStream();
        // 2.使用数组接收流信息
        byte[] bytes = new byte[length];
        inputStream.read(bytes);
        // 3.将数组转换成字符串(或对象)
        String result = new String(bytes, "utf-8");
        System.out.println(result);

        //4.字符串转换成对象(或字典)
        ObjectMapper objectMapper=new ObjectMapper();
        HashMap<String,String> map=objectMapper.readValue(result,HashMap.class);
        System.out.println("用户名:"+map.get("username"));
        System.out.println("密码:"+map.get("password"));
        resp.getWriter().println("用户名:"+map.get("username")+"|密码:"+map.get("password"));
    }
}

JSON前端请求代码:
login-ajax-json.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录系统</title>
    <script src="js/jquery-1.9.1.min.js"></script>
</head>
<body>
<div style="margin-top:50px;margin-left:40%">
    <h1 style="padding-left:50px">用户登录</h1>
    姓名:<input id="username" type="text" name="username">
    <p>
        密码:<input id="password" type="password" name="password">
    <p>
    <div style="padding-left:50px">
        <input  type="button" value="提 交" onclick="mySubmit()">&nbsp;&nbsp;&nbsp;&nbsp;
        <input type="reset" value="重 置">
    </div>
</div>
<script>
     function mySubmit(){
      <!-- 非空效验  -->
      var username=jQuery("#username");
      var password=jQuery("#password");
      if("" == username.val()){
           alert("请先输入用户名!")
           username.focus();
           return;
      }
      if(""==password.val()){
            alert("请先输入密码!");
            return;
      }

         jQuery.ajax({
             url:"postjson",//设置请求地址
             type:"POST",//设置请求方法类型
             contentType:"application/json; charset=utf-8",//请求类型
             //dataType:"",//响应的类型
             //将对象转换成json字符串
             data:JSON.stringify({"username":username.val(),"password":password.val()}),
             success:function(data){
             alert(data);
             }
         });
     }
</script>
</body>
</html>

注意:
(1)Jackson 库的核⼼类为 ObjectMapper. 其中的 readValue ⽅法把⼀个 JSON 字符串转成 Java 对象. 其中的 writeValueAsString ⽅法把⼀个 Java 对象转成 JSON 格式字符串.
(2)readValue 的第⼆个参数为 JsonData 的 类对象. 通过这个类对象, 在 readValue 的内部就可以借助 反射机制来构造出 JsonData 对象, 并且根据 JSON 中key 的名字, 把对应的 value 赋值给 JsonData 的对应字段.

使用Fiddler抓包:

2.2.7 使用 postman模拟发送请求

postman常用方法:

3.HttpServletResponse

核心方法:

注意:
响应对象是服务器要返回给浏览器的内容, 这⾥的重要信息都是自己设置的. 因此上⾯的⽅法都 是 “写” 方法.
对于状态码/响应头的设置要放到 getWriter / getOutputStream 之前. 否则可能设置失效.

设置状态码

实现一个程序,用户在浏览器通过参数指定要返回响应的状态码。

state=200:

使用Fiddler抓包:

state=404:


state=500:

自动刷新

1.实现一个程序,让浏览器每秒钟自动刷新一次,并显示当前的时间戳。
RefreshServlet.java:

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.time.LocalDateTime;

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Refresh","1");
        resp.getWriter().println(""+LocalDateTime.now());
    }
}


2.配置servlet的jdk版本:
(1) project:
(2)Modules:

(3)java Compiler:

(4)pom.xml:

重定向

实现一个程序,返回一个重定向HTTP响应,自动跳转到另外一个页面。
1.第一个例子:



LoginServlet.java:

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("/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String result = "未知错误";
        // 1.得到参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        // 2.业务处理
        // 非空效验
        if (null != username && null != password &&
                !username.equals("") && !password.equals("")) {
            if (username.equals("admin") && password.equals("admin")) {
                result = "恭喜:登录成功!";
            } else {
                result = "登录失败,用户名或密码输入错误,请检查!";
            }
        } else {
            result = "非法参数!";
        }

        resp.setContentType("text/html; charset=utf-8");

        // 3.将结果返回给前端
        resp.getWriter().write(result);
    }
}


MainServlet.java:

import utils.StringUtils;
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("/main")
public class MainServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String token = req.getParameter("token");
        if (!StringUtils.hasLength(token) && "admin".equals(token)){
            resp.setContentType("text/html");
            resp.setCharacterEncoding("utf-8");
            resp.getWriter().println("欢迎您:系统管理员!");
        }else{
            //未授权,调转到登录页面
            resp.sendRedirect("http://localhost:8080/first-servlet/login.html");
        }
    }
}


运行结果:



如果用户名错误就会重定向到登录页面:

用Fiddler抓包观察重定向:


2.第二个例子:

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("/redirectServlet")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        resp.sendRedirect("http://www.sogou.com");
    }
}


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/920355.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存