0


Servlet API

文章目录

1. Servlet API

1.1 HttpServlet

方法

方法名称调用时机init在 HttpServlet 实例化之后被调用一次destory在 HttpServlet 实例不再使用的时候调用一次service收到 HTTP 请求的时候调用doGet收到 GET 请求的时候调用(由 service 方法调用)doPost收到 POST 请求的时候调用(由 service 方法调用)doPut/doDelete/doOptions/…收到其他请求的时候调用(由 service 方法调用)
我们实际开发的时候很少会重写 init / destory / service

这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程)

这里会有一道面试题: 说一下 Servlet 的生命周期

  1. Servlet 在实例化之后调用一次 init()
  2. Servlet 在每次收到请求调用一次 service()
  3. Servlet 在销毁之前,调用一次 destroy()

在这里插入图片描述

代码示例: 处理 GET 请求 和 POST 请求

java代码

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/method")publicclassMethodServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("GET 响应");}@OverrideprotectedvoiddoPost(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("text/html;charset=utf-8");
        resp.getWriter().write("POST 响应");}}

使用前端代码进行测试.

<!doctypehtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><metahttp-equiv="X-UA-Compatible"content="ie=edge"><title>Document</title></head><body><buttononclick="getMethod()">发送 GET 请求</button><buttononclick="postMethod()">发送 POST 请求</button><scriptsrc="https://releases.jquery.com/git/jquery-3.x-git.min.js"></script><script>functiongetMethod(){
            $.ajax({type:"get",url:"method",success:function(data,status){
                    console.log(data);}})}functionpostMethod(){
            $.ajax({type:"post",url:"method",data:"request body",success:function(data,status){
                    console.log(data);}})}</script></body></html>

浏览器按F12可以查看
在这里插入图片描述
使用 Postman 测试
在这里插入图片描述

在这里插入图片描述

1.2 HttpServletRequest

方法

方法描述String getProtocol()返回请求协议的名称和版本。String getMethod()返回请求的 HTTP 方法的名称,例如,GET、POST 或 PUT。String getRequestURI()从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分。String getContextPath()返回指示请求上下文的请求 URI 部分。String getQueryString()返回包含在路径后的请求 URL 中的查询字符串。Enumeration getParameterNames()返回一个 String 对象的枚举,包含在该请求中包含的参数的名称。String getParameter(String name)以字符串形式返回请求参数的值,或者如果参数不存在则返回null。String[] getParameterValues(String name)返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null。Enumeration getHeaderNames()返回一个枚举,包含在该请求中包含的所有的头名。String getHeader(String name)以字符串形式返回指定的请求头的值。String getCharacterEncoding()返回请求主体中使用的字符编码的名称。String getContentType()返回请求主体的 MIME 类型,如果不知道类型则返回 null。int getContentLength()以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1。InputStream getInputStream() 用于读取请求的 body 内容. 返回一个 InputStream 对象.

代码示例: 打印请求方式

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.util.Enumeration;@WebServlet("/show")publicclassShowServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("text/html; charset=utf-8");// 将 生成的响应的body 放入到 respBody 中StringBuilder respBody =newStringBuilder();
        respBody.append(req.getProtocol()+"<br>");
        respBody.append(req.getMethod()+"<br>");
        respBody.append(req.getRequestURI()+"<br>");
        respBody.append(req.getContextPath()+"<br>");

        respBody.append("<h1>headers:</h1>");Enumeration<String> enumeration = req.getHeaderNames();while(enumeration.hasMoreElements()){String headerName = enumeration.nextElement();
            respBody.append(headerName +": ");
            respBody.append(req.getHeaders(headerName)+"<br>");}

        resp.getWriter().write(respBody.toString());}}

在这里插入图片描述

代码示例: 获取 GET 请求中的参数

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/parameter")publicclassGetParameterServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("text/html; charset=utf-8");String userId = req.getParameter("userId");String classId = req.getParameter("classId");
        resp.getWriter().write("userId: "+ userId +","+"classId: "+ classId);}}

在浏览器中输入

http://127.0.0.1:8080/Servlet/parameter

,此时是null,因为当前没有 query string
在这里插入图片描述
在浏览器中输入

http://127.0.0.1:8080/Servlet/parameter?userId=500&classId=1

在这里插入图片描述

代码示例: 获取 POST 请求中的参数(form表单按钮)

java代码

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/postParameter")publicclassPostParameterServletextendsHttpServlet{@OverrideprotectedvoiddoPost(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("text/html; charset=utf-8");String userId = req.getParameter("userId");String classId = req.getParameter("classId");
        resp.getWriter().write("userId: "+userId+","+"classId: "+classId);}}

html 代码

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>Title</title></head><body><formaction="postParameter"method="POST"><inputtype="text"name="userId"><inputtype="text"name="classId"><inputtype="submit"value="提交"></form></body></html>

输入 123 ,456之后提交
在这里插入图片描述
在这里插入图片描述

代码示例: 获取 POST 请求中的参数(JSON格式)

这里要导入一个 Json库
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

importcom.fasterxml.jackson.databind.ObjectMapper;importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;importjava.io.InputStream;classJsonData{publicint userId;publicint classId;}@WebServlet("/Json")publicclassPostJsonServletextendsHttpServlet{@OverrideprotectedvoiddoPost(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("application/json;charset=utf-8");String respBody =readBody(req);ObjectMapper objectMapper =newObjectMapper();JsonData jsonData = objectMapper.readValue(respBody,JsonData.class);
        resp.getWriter().write("userId: "+ jsonData.userId+","+"classId: "+jsonData.classId);}privateStringreadBody(HttpServletRequest req)throwsIOException{int contentLength = req.getContentLength();byte[] buffer =newbyte[contentLength];InputStream inputStream = req.getInputStream();
        inputStream.read(buffer);returnnewString(buffer,"utf-8");}}

在这里插入图片描述

1.3 HttpServletResponse

方法

方法描述void setStatus(int sc)为该响应设置状态码。void setHeader(String name,String value)设置一个带有给定的名称和值的 header. 如果 name 已经存在,则覆盖旧的值.void addHeader(String name, String value)添加一个带有给定的名称和值的 header. 如果 name 已经存在,不覆盖旧的值, 并列添加新的键值对void setContentType(String type)设置被发送到客户端的响应的内容类型。void setCharacterEncoding(String charset)设置被发送到客户端的响应的字符编码MIME 字符集)例如,UTF-8。void sendRedirect(String location)使用指定的重定向位置 URL 发送临时重定向响应到客户端。PrintWriter getWriter()用于往 body 中写入文本格式数据.OutputStream getOutputStream()用于往 body 中写入二进制格式数据.

代码示例: 设置状态码

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/status")publicclassStatusServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{String status = req.getParameter("status");if(status !=null){
            resp.setStatus(Integer.parseInt(status));}
        resp.getWriter().write("status: "+status);}}

在这里插入图片描述
在这里插入图片描述

代码示例: 自动刷新

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/refresh")publicclassAutoRefreshServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setHeader("Refresh","1");long time =System.currentTimeMillis();
        resp.getWriter().write(time+"");}}

每次刷新都会有一个HTTP请求
在这里插入图片描述

代码示例: 重定向

importjavax.servlet.ServletException;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.io.IOException;@WebServlet("/redirect")publicclassRedirectServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setStatus(302);// resp.setHeader("Location","http://www.baidu.com");
        resp.sendRedirect("http://www.baidu.com");}}

直接从

http://127.0.0.1:8080/Servlet/redirect

跳转到了

https://www.baidu.com/

在这里插入图片描述

1.4 上传文件

方法

HttpServletRequest 类方法

方法描述Part getPart(String name)获取请求中给定 name 的文件Collection getParts()获取所有的文件

Part 类方法

方法描述String getSubmittedFileName()获取提交的文件名String getContentType()获取提交的文件类型long getSize()获取文件的大小void write(String path)把提交的文件数据写入磁盘文件

代码示例: 上传文件

首先写好前端代码

<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Document</title></head><body><formaction="upload"method="POST"enctype="multipart/form-data"><inputtype="file"name="myImage"><inputtype="submit"value="提交图片"></form></body></html>

写java代码,一定要写一个注解

@MultipartConfig
importjavax.servlet.ServletException;importjavax.servlet.annotation.MultipartConfig;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjavax.servlet.http.Part;importjava.io.IOException;@MultipartConfig@WebServlet("/upload")publicclass uploadServlet extendsHttpServlet{@OverrideprotectedvoiddoPost(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{// 1. 从 req 对象中,读取 Part 对象Part part = req.getPart("myImage");// 2. 读取到 Part 对象中的一些参数// 这里是打印 上传文件的真实文件名System.out.println(part.getSubmittedFileName());// 这里是打印 文件的类型System.out.println(part.getContentType());// 这里是打印 文件的大小System.out.println(part.getSize());// 3. 将文件写入指定目录
        part.write("D:/gihub创库/JavaEE_CODE/image/myImage.jpg");// 4. 返回一个响应
        resp.getWriter().write("upload successful");}}

结果演示:
选择一个图片,点击提交
在这里插入图片描述
在这里插入图片描述
查看抓包的结果
请求:
在这里插入图片描述
响应:
在这里插入图片描述
服务器运行结果
在这里插入图片描述

2. 实现一个 Web 版 表白墙

2.1 首先创建好一个 maven 项目

  1. 新建 maven 项目
  2. 创建目录 webapp/WEB-INF/web.xml在这里插入图片描述 在web.xml写入
<!DOCTYPEweb-appPUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd"><web-app><display-name>Archetype Created Web Application</display-name></web-app>
  1. 引入依赖 servlet 和 Jackson在这里插入图片描述在这里插入图片描述
  2. 将之前所写的 表白墙的前端代码拷贝到webapp中在这里插入图片描述

2.2 约定好前后端交互接口

① 从服务器上获取留言的内容

在这里插入图片描述

② 发表新的留言到服务器上

在这里插入图片描述

2.3 服务器端代码

首先创建一个

Confession

classConfession{publicString from;publicStringto;publicString message;}

创建一个

confessionServlet

类 继承

HttpServlet

重写

doGet

doPost

方法,注解

@WebServlet("/confession")

创建一个

objectMapper对象

用于转换 JSON 字符串

privateObjectMapper objectMapper =newObjectMapper();

① 重写 doGet 方法

这里是为了处理从服务器上获取到消息.

// 这个用来处理从服务器获取到消息数据@OverrideprotectedvoiddoGet(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{
        resp.setContentType("application/json;charset=utf-8");// 这里的 load() 是用来 读取服务器上的数据List<Confession> confessionList =load();
        objectMapper.writeValue(resp.getWriter(),confessionList);}

② 重写 doPost 方法

这是为了处理提交留言到服务器上

// 这个用来处理客户端提交数据给服务器@OverrideprotectedvoiddoPost(HttpServletRequest req,HttpServletResponse resp)throwsServletException,IOException{Confession confession = objectMapper.readValue(req.getInputStream(),Confession.class);// 这里的 save() 是用来 提交数据在服务器上save(confession);

        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().write("{\"ok\":1}");}

2.4 数据存储

由于每次刷新页面,数据就不见了.想要每次输入的数据都在,就要将数据存起来.有两种方法.一种是存文件的方法,一种是存数据库的方法.

1) 存文件的方式存储

创建一个

filePath

保存文件的存储路径

privateString filePath ="d:/confessionWall.txt";

约定好存文件的格式.每行是一个数据,每个数据的内容之间用

\t

隔开

① 使用文件的方法实现 load()

/**
     * 向文件夹中加载数据
     * @return
     */privateList<Confession>load(){List<Confession> confessionList =newArrayList<>();// 此处我们需要按行读取. FileReader 本身不支持. 需要套上一层 BufferedReadertry(BufferedReader bufferedReader =newBufferedReader(newFileReader(filePath))){while(true){String line = bufferedReader.readLine();// line=null的时候 读完了if(line ==null){break;}// 设定存储的时候每行的内容是按 \t 的方法存储// 所以读取每行,然后按 \t的方法进行 分割String[] res = line.split("\t");Confession confession =newConfession();
                confession.from = res[0];
                confession.to= res[1];
                confession.message = res[2];

                confessionList.add(confession);}}catch(IOException e){
            e.printStackTrace();}return confessionList;}

② 使用文件的方法实现 save()

/**
     * 向文件夹中写入数据
     * @param confession
     */privatevoidsave1(Confession confession){// 这里的 true 表示追加写状态,表示不清空文件,而是从文件后面继续写try(FileWriter fileWriter =newFileWriter(filePath,true)){// 按照约定好的方法写入数据
            fileWriter.write(confession.from+"\t"+confession.to+"\t"+confession.message+"\n");}catch(IOException e){
            e.printStackTrace();}}

2) 存数据库的方式存储

首先创建一个类

ConnectionDB

用来连接数据库

pom.xml

中引入

mysql jdbc

的依赖

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.17</version></dependency>

类 ConnectionDB

importcom.mysql.cj.jdbc.MysqlDataSource;importjavax.sql.DataSource;importjava.sql.Connection;importjava.sql.PreparedStatement;importjava.sql.ResultSet;importjava.sql.SQLException;publicclassConnectionDB{privatestaticfinalString URL="jdbc:mysql://127.0.0.1:3306/confessionWall?characterEncoding=utf-8&useSSL=true&serverTimezone=UTC";privatestaticfinalString USERNAME ="root";privatestaticfinalString PASSWORD ="0000";// 这里的volatile 和 synchronized 相当于懒汉模式privatestaticvolatileDataSource dataSource =null;publicstaticDataSourcegetDataSource(){if(dataSource ==null){synchronized(ConnectionDB.class){if(dataSource ==null){
                    dataSource =newMysqlDataSource();((MysqlDataSource) dataSource).setURL(URL);((MysqlDataSource) dataSource).setUser(USERNAME);((MysqlDataSource) dataSource).setPassword(PASSWORD);}}}return dataSource;}publicstaticConnectiongetConnection()throwsSQLException{returngetDataSource().getConnection();}publicstaticvoidclose(Connection connection,PreparedStatement statement,ResultSet resultSet){if(resultSet !=null){try{
                resultSet.close();}catch(SQLException e){
                e.printStackTrace();}}if(statement !=null){try{
                statement.close();}catch(SQLException e){
                e.printStackTrace();}}if(connection !=null){try{
                connection.close();}catch(SQLException e){
                e.printStackTrace();}}}}

数据库中的代码

createdatabase confessionWall;use confessionWall;createtable confession(`from`varchar(1024),`to`varchar(1024),`message`varchar(1024));

① 使用数据库的方法实现 load()

/**
     * 从数据库中读取数据
     * @return
     */privateList<Confession>load(){List<Confession> confessionList =newArrayList<>();Connection connection =null;PreparedStatement statement =null;ResultSet resultSet =null;try{// 和数据库建立连接
            connection =ConnectionDB.getConnection();// 借助 PreparedStatement 拼接 SQL 语句String sql ="select * from confession";
            statement = connection.prepareStatement(sql);// 执行 SQL 语句 
            resultSet = statement.executeQuery();// 遍历结果集while(resultSet.next()){Confession confession =newConfession();
                confession.from = resultSet.getString("from");
                confession.to= resultSet.getString("to");
                confession.message = resultSet.getString("message");
                confessionList.add(confession);}}catch(SQLException throwables){
            throwables.printStackTrace();}finally{// 关闭释放资源ConnectionDB.close(connection,statement,resultSet);}return confessionList;}

② 使用数据库的方法实现 save()

/**
     * 从数据库中写入数据
     * @param confession
     */privatevoidsave(Confession confession){Connection connection =null;PreparedStatement statement =null;try{// 1. 先和数据库建立连接
            connection =ConnectionDB.getConnection();// 2. 构造拼装 SQLString sql ="insert into confession values (?,?,?)";// 这里的 ? 号是占位符,下标是从1开始
            statement = connection.prepareStatement(sql);
            statement.setString(1,confession.from);
            statement.setString(2,confession.to);
            statement.setString(3,confession.message);// 3. 执行 SQLint ret = statement.executeUpdate();// 这里 ret 表示的是受影响的行数,如果为1才是插入成功if(ret ==1){System.out.println("插入成功!");}else{System.out.println("插入失败!");}}catch(SQLException throwables){
            throwables.printStackTrace();}finally{// 4. 关闭释放资源ConnectionDB.close(connection,statement,null);}}

2.5 修改前端代码

首先加入 jquery

<scriptsrc="https://releases.jquery.com/git/jquery-git.min.js"></script>

① 加载页面的时候从服务器获取内容

<script>// 1. 在页面加载的时候,访问服务器,从服务器获取到的消息列表,并展示出来functionload(){
            $.ajax({// 类型约定好了的是 GET ,url也约定好了是 confessiontype:"GET",url:"confession",success:function(data,status){// data 是响应的 body// 这里的 .parent 是根据之前写的代码来决定的let parent = document.querySelector('.parent');// 由于data存储的时候自动变成了数组的形式// 如果没有变还需要 自己进行解析 JSON.parse(data);let messages = data;for(let message of messages){let row = document.createElement('div');
                        row.className ='elem';
                        row.innerHTML = message.from +'对'+ message.to +'说: '+ message.message;
                        parent.appendChild(row);}}});}load();</script>

② 点击提交按钮的时候,把当前的数据构造一个HTTP请求,发给服务器

<script>// 这里需要构造一个 HTTP 请求.把消息发送给服务器保存起来
            
            $.ajax({type:"POST",url:"confession",// 将body的内容变成json的格式data:JSON.stringify({from: user1,to: user2,message: message}),contentType:"application/json; charset=utf-8",success:function(data,status){if(data.ok ==1){
                        console.log("提交消息成功!");}else{
                        console.log("提交失败!");}}});</script>

2.6 运行结果图

文件的方式

首次进入页面没有内容
在这里插入图片描述
输入 小明 对 小强 说 hello
输入 小强 对 小红 说 你真好
在这里插入图片描述
刷新页面或者重启服务器.该页面的内容都在. 查看路径

d:/confessionWall.txt

下的文件内容
在这里插入图片描述

数据库的方式

首次访问还没有数据
在这里插入图片描述
输入 小明 对 小红 说 你好
输入 小红 对 小明 说 你也好
在这里插入图片描述
刷新页面或者重启服务器.该页面的内容都在.查看数据库
在这里插入图片描述

2.7 总结

  1. 数据存储的方式使用 文件 还是 数据库.主要是根据具体情况来看的 当前我们写的程序比较简单, 存储的数据比较少, 数据格式也不复杂. 这种情况下使用文件是比数据库代码更精简一些 当前我们的程序更复杂, 数据更多并且数据格式也更复杂的时候.这种情况下使用数据库的代码更好. 例如 表白墙 这种 就更适合于 文件
  2. 在写 Web 程序的时候, 首先要约定好前后端交互的具体方法.不然前端代码和后端代码就可能不在一条路上
  3. 在出错的时候,在网页中按F12进行查看,是前端代码出错还是后端代码出错.如果前端出错再去改前端代码,后端出错再去改后端代码.
标签: web java

本文转载自: https://blog.csdn.net/wwzzzzzzzzzzzzz/article/details/124431639
版权归原作者 wwzzzzzzzzz 所有, 如有侵权,请联系我们删除。

“Servlet API”的评论:

还没有评论