Tomcat、Servlet的部署与使用

目录

 前言

Tomcat

Tomcat的部署

 Tomcat的使用

Servlet

第一个servlet程序

Smart Tomcat

访问出错

404

405

500

 出现“空白页面”

 出现“无法访问此网站”

Servlet API 

HttpServlet

核心方法

Servlet的生命周期

HttpServletRequest

核心方法

打印请求信息

 获取GET请求中的参数

获取post请求中body中的参数

HttpServletResponse

核心方法 

设置状态码

自动刷新

构造一个重定向响应

表白墙


 前言

继续接着后端的学习,本篇博客我们主要设计Tomcat以及Servlet的部署,还有Servlet的使用方法!!!

Tomcat

Tomcat是一个HTTP服务器

Tomcat的部署

1、选择Tomcat8即可

2、直接解压缩 

 3、解压后的文件夹,找到bin目录下的startup.bat,双击点击启动

 看到这个信息,就证明启动成功了

4、Tomcat默认端口是8080,当出现这个欢迎页面时,就证明tomcat跑起来了

 Tomcat的使用

1、将html代码拷贝至webapps目录下

2、在浏览器输入127.0.0.1:8080/代码名称

Servlet

Servlet是一种实现动态页面的技术,是一组Tomcat提供给程序员的API,用来构建动态页面这个任务

第一个servlet程序

1、创建项目

创建一个maven项目

 项目创建好了之后的目录结构

2、引入servlet依赖

maven的一个核心功能,就是能够自动的管理依赖,就会把咱们使用的库里依赖的东西,自动从中央仓库上,下载下来

 选择3.1.0版本

选择maven,把maven里的代码复制下来,粘贴到pom.xml中

3、创建目录结构

创建webapp目录

 在webapp目录下,创建一个WEB-INF目录,并创建一个web.xml文件

 将这段代码放入web.xml中

4、编写代码

在java目录下创建package

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;

/**
 * @author krystal
 * @date 2022/12/1 10:36
 */

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //是tomcat这边打印个日志
        System.out.println("hello");
        //还可以给客户端返回个hello
        resp.getWriter().write("hello");
    }
}

此时doGet所做的工作,就是“根据请求计算响应”,req对象,这是Tomcat把HTTP请求报文,解释成一个对象了,resp对象,则是Tomcat构造的一个空的对象(resp相当于一个“输出型参数”)

doGet就需要根据req里的一些数据+业务逻辑构造生成一个完整的resp对象,在进一步,tomcat就把resp对象转成一个HTTP响应报文

5、打包程序

使用maven进行打包,打开maven窗口双击package 

 打包成功

成功后,我们可以在target目录下,生成一个jar包

tomcat要求的压缩包格式,是war包,这就需要我们修改pom.xml,添加以下代码

6、部署程序

把war包拷贝到tomcat的webapps中

重新启动tomcat 

7、验证程序

通过浏览器,构造一个HTTP请求,来访问Tomcat服务器

Smart Tomcat

以上步骤可以简化操作,“一键式”打包和部署,可以使用第三方的Smart Tomcat插件来完成

 配置smart tomcat插件

 这里需要手动配置Context Path

tomcat的运行方式:

1、直接在startup这里运行,手动拷贝war包过去;

2、直接通过java代码,调用tomcat的jar包运行,则不需要调用的时候指定tomcat加载哪个webapp(只能加载一个)(smart tomcat的方式)

访问出错

404

1、路径写错了;

2、webapp没有被tomcat正确加载

错误实例1:少写了Context Path

 错误实例2:少写了Servlet Path

 错误实例3:Servlet Path和URL不匹配

 错误实例4:web.xml写错了

405

对应的HTTP请求方法没有实现

还有一种情况:忘记删除super.do代码

500

服务器代码抛异常

 出现“空白页面”

响应数据的操作可能没有执行到

 出现“无法访问此网站”

tomcat没有启动或者ip/端口写错了

Servlet API 

HttpServlet

核心方法

方法名称调用时机
init
HttpServlet 实例化之后被调用一次
destroy
HttpServlet 实例不再使用的时候调用一次
service
收到 HTTP 请求的时候调用
doGet
收到 GET 请求的时候调用 ( service 方法调用 )
doPost
收到 POST 请求的时候调用 ( service 方法调用 )
doPut/doDelete/doOptions/...
收到其他请求的时候调用 ( service 方法调用 )

Servlet的生命周期

初始阶段,实例化的时候,调用一次init

结束销毁之前,调用一次destroy

每次收到请求,调用service 

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 对象 .

打印请求信息

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;

/**
 * @author krystal
 * @date 2022/12/1 15:30
 */
@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append(req.getProtocol());
        stringBuilder.append("\n");
        stringBuilder.append(req.getMethod());
        stringBuilder.append("\n");
        stringBuilder.append(req.getRequestURI());
        stringBuilder.append("\n");
        stringBuilder.append(req.getContextPath());
        stringBuilder.append("\n");
        stringBuilder.append(req.getQueryString());
        stringBuilder.append("\n");

        //把请求的header也拼进来
        Enumeration<String> headNames=req.getHeaderNames();
        while (headNames.hasMoreElements()){
            String name=headNames.nextElement();
            String value=req.getHeader(name);
            stringBuilder.append(name+":"+value);
            stringBuilder.append("\n");
        }

        resp.getWriter().write(stringBuilder.toString());
        //System.out.println(stringBuilder.toString());
    }
}

 获取GET请求中的参数

GET请求中的参数一般都是通过query string传递给服务器的,在服务器端就可以通过getParameter来获取到参数的值

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;

/**
 * @author krystal
 * @date 2022/12/1 16:15
 */
@WebServlet("/getParameter")
public class GetParameterServlet extends HelloServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取 query string 中的键值对.
        // 假设浏览器的请求形如 ?studentId=10&studentName=张三
        String studentId = req.getParameter("studentId");
        String studentName = req.getParameter("studentName");
        System.out.println(studentId);
        System.out.println(studentName);

        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(studentId + ", " + studentName);
    }
}

获取post请求中body中的参数

 1、请求的body是x-www-form-urlencoded,使用getParameter来获取的

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过body获取,发个post请求
        String studentId = req.getParameter("studentId");
        String studentName = req.getParameter("studentName");
        System.out.println(studentId);
        System.out.println(studentName);

        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write(studentId + ", " + studentName);
    }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="getParameter" method="post">
        <input type="text" name="studentId">
        <input type="text" name="studentName">
        <input type="submit" value="提交">
    </form>
</body>
</html>

还可以使用postman构造这种请求

2、请求的body是json

import com.fasterxml.jackson.databind.ObjectMapper;

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;

/**
 * @author krystal
 * @date 2022/12/1 17:35
 */
class Student{
    //1、这个类里的属性必须是public或者带有public的getter和setter
    //   否则,jackson无法访问这个对象的属性
    //2、这个类务必要有无参版本的构造方法,如果不写任何构造方法,编译器能自动生成无参构造
    public int studentId;
    public String studentName;
}

@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //jackson提供的核心的类
        //一个方法为readValue,把json格式的数据转成java对象
        //一个方法为writeValueAsString,把json对象转成json格式的字符串
        ObjectMapper objectMapper=new ObjectMapper();
        //readValue第一个参数可以是字符串,也可以时输入流
        //第二个参数,是一个类对象,也就是要解析出来的结果的对象的类
        Student s=objectMapper.readValue(req.getInputStream(),Student.class);
        System.out.println(s.studentId);
        System.out.println(s.studentName);

//        resp.setContentType("text/html;charset=utf8");
//        resp.getWriter().write(s.studentId+","+s.studentName);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(objectMapper.writeValueAsString(s));
    }
}

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 中写入二进制格式数据 .

设置状态码

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;

/**
 * @author krystal
 * @date 2022/12/1 19:04
 */
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //约定,浏览器query string传个参数过来
        String type=req.getParameter("type");
        if (type.equals("1")){
            resp.setStatus(200);
        }else if (type.equals("2")){
            resp.setStatus(404);
            //返回tomcat自带的错误页面
            resp.sendError(404);
        }else if (type.equals("3")){
            resp.setStatus(500);
        }else {
            resp.setStatus(504);
        }
    }
}

自动刷新

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;

/**
 * @author krystal
 * @date 2022/12/1 19:22
 */
@WebServlet("/autoRefresh")
public class AutoRefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //直接返回响应就好
        resp.setHeader("refresh","2");
        resp.getWriter().write(System.currentTimeMillis()+"");
    }
}

构造一个重定向响应

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;

/**
 * @author krystal
 * @date 2022/12/1 19:41
 */
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(302);
        resp.setHeader("Location","https://www.sogou.com");
    }
}

表白墙

需要让用户留言的数据能够在服务器这边保存,就可以保证页面关闭,数据不会丢失

1、创建项目,引入依赖,创建目录结构

2、设计前后端如何交互(什么时候发请求,发的请求什么样,返回的响应什么样)

/**
 * @author krystal
 * @date 2022/12/1 22:46
 */
public class Message {
    private String from;
    private String to;
    private String message;

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;

/**
 * @author krystal
 * @date 2022/12/2 9:17
 */
public class DBUtil {
    private static volatile DataSource dataSource=null;

    public static DataSource getDataSource(){
        if (dataSource==null){
            synchronized (DBUtil.class){
                if (dataSource==null){
                    dataSource=new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/bb?characterEncoding=utf8&useSSL=false");
                    ((MysqlDataSource)dataSource).setUser("root");
                    ((MysqlDataSource)dataSource).setPassword("19930112");
                }
            }
        }
        return dataSource;
    }

    private DBUtil(){

    }
}

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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 javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author krystal
 * @date 2022/12/1 19:57
 */
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    private ObjectMapper objectMapper=new ObjectMapper();
    //负责让页面获取到数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf8");
        List<Message> messageList= null;
        try {
            messageList = load();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.getWriter().write(objectMapper.writeValueAsString(messageList));
    }

    //提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取body中的数据并解析
        Message message=objectMapper.readValue(req.getInputStream(),Message.class);
        //将数据保存在内存中
        //messageList.add(message);
        try {
            save(message);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.setStatus(200);
        System.out.println("提交数据成功!from="+message.getFrom()+",to="+message.getTo()+",message="+message.getMessage());
    }

    private List<Message> load() throws SQLException {
        //从数据库查询数据
        //1、先有一个数据源
        DataSource dataSource=DBUtil.getDataSource();

        //2、建立连接
        Connection connection=dataSource.getConnection();

        //3、构造sql语句
        String sql="select * from message";
        PreparedStatement statement=connection.prepareStatement(sql);

        //4、执行sql
        ResultSet resultSet =statement.executeQuery();

        //5、遍历结果集合
        List<Message> messageList=new ArrayList<>();
        while (resultSet.next()){
            Message message=new Message();
            message.setFrom(resultSet.getString("from"));
            message.setTo(resultSet.getString("to"));
            message.setMessage(resultSet.getString("message"));
            messageList.add(message);
        }

        //5、关闭连接
        statement.close();
        connection.close();
        return messageList;
    }

    private void save(Message message) throws SQLException {
        //保存数据

        //1、先有一个数据源
        DataSource dataSource=DBUtil.getDataSource();

        //2、建立连接
        Connection connection=dataSource.getConnection();

        //3、构造sql语句
        String sql="insert into message values(?,?,?)";
        PreparedStatement statement=connection.prepareStatement(sql);
        statement.setString(1,message.getFrom());
        statement.setString(2,message.getTo());
        statement.setString(3,message.getMessage());

        //4、执行sql
        int ret=statement.executeUpdate();
        System.out.println("ret="+ret);

        //5、关闭连接
        statement.close();
        connection.close();
    }
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>
</head>
<body>
    <style>
        .container{
            width: 400px;
            margin: 0 auto;
        }

        h1{
            text-align: center;
        }

        p{
            text-align: center;
            color: #666;
        }

        .row{
            height: 40px;
            display: flex;
            /* 水平居中 */
            justify-content: center;
            /* 垂直居中 */
            align-items: center;
        }

        .row span{
            width: 100px;
        }

        .row input{
            width: 200px;
            height: 20px;
        }

        .row button{
            width: 310px;
            height: 30px;
            color: white;
            background-color: orange;
            border: none;
        }

        .row button:active{
            background-color: #666;
        }
    </style>

    <div class="container">
        <h1>表白墙</h1>
        <p>输入后点击提交,就会把信息显示在表格中</p>
        <div class="row">
            <span>谁:</span><input type="text">
        </div>
        <div class="row">
            <span>对谁:</span><input type="text">
        </div>
        <div class="row">
            <span>说什么:</span><input type="text">
        </div>
        <div class="row">
            <button>提交</button>
        </div>
    </div>

    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

    <script>
        let container=document.querySelector('.container');
        let button=document.querySelector('button');
        button.onclick=function(){
            //1.获取到输入框的内容
            let inputs=document.querySelectorAll('input');
            let from=inputs[0].value;
            let to=inputs[1].value;
            let message=inputs[2].value;
            if(from=='' || to=='' || message==''){
                alert('输入的内容为空');
                return;
            }
            console.log(from+','+to+','+message);
            //2.能够构造出新的div,用来保存用户提交的内容
            let rowDiv=document.createElement('div');
            rowDiv.className='row';
            rowDiv.innerHTML=from+"对"+to+"说:"+message;
            container.appendChild(rowDiv);
            //3.提交完后,清空输入框的内容
            for(let i=0;i<inputs.length;i++){
                inputs[i].value='';
            }

            let data={
                from:from,
                to:to,
                message:message
            };

            //4、点击发送按钮,给服务器发送个post请求
            $.ajax({
                type:'post',
                url:'message',
                //这里放的是body的内容
                data:JSON.stringify(data),
                contentType:"application/json;charset=utf8",
                success:function(body){
                    console.log("提交数据成功");
                }
            });
        }

        // 直接写在 script 标签里的代码, 都是在页面加载的时候执行的. 
        // 来获取服务器的数据
        function getMessage(){
            $.ajax({
                type:"get",
                url:"message",
                success:function(body){
                    // body 就是响应的 body 内容, json 数组. 
                    // jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
                    // 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
                    for(let i=0;i<body.length;i++){
                        let message=body[i];
                        let row=document.createElement('div');
                        row.className='row';
                        row.innerHTML=message.from+"对"+message.to+"说"+message.message;
                        container.appendChild(row);
                    }
                }
            });
        }

        getMessage();
        
    </script>
</body>
</html>
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值