Servlet(一些实战小示例)

文章目录

  • 一、实操注意点
    • 1.1 代码修改重启问题
    • 1.2 Smart Tomcat的日志
    • 1.3 如何处理错误
  • 一. 抓自己的包
  • 二、构造一个重定向的响应,让页面重定向到百度主页
  • 三、让服务器返回一个html数据
  • 四、表白墙
    • 4.1 约定前后端数据
    • 4.2 前端代码
    • 4.3 后端代码
    • 4.4 保存在数据库的版本

一、实操注意点

1.1 代码修改重启问题

编写Servlet程序时,无论是修改前端还是后端代码都需要重新启动服务器

  • 后端Java代码需要重启来重新编译
  • 前端的静态页面可能会被Tomcat给提前加载并缓存在内存中,如果不重启,修改的前端代码可能不会同步到内存中

1.2 Smart Tomcat的日志

Smart Tomcat为了开发方便,将日志直接显示到了IDEA窗口里,并没有专门生成日志文件

  • 因为开发阶段日志只是起到调试作用,需要反复修改代码
  • 等到程序发布,就一定要把日志保存到文件中,此时日志是记录了服务器的运行状态

1.3 如何处理错误

  1. 判断前端 or 后端问题:通过fidder抓包判断
    • 如果抓包发现 ajax 的http请求根本没发出来,那大概率就是前端问题
    • 如果ajax的http请求发了,且内容符合要求,那大概率是后端问题
  2. 处理前端问题:去浏览器的开发者工具上看,不要看VSCode里的前端代码,因为js代码都是被下载到浏览器后执行的
    • F12或右键检查打开开发者工具,source部分表示了当前浏览器加载了哪些前端代码
    • JS代码编译问题:JS代码在执行过程中,并不像Java有先编译的过程,而是直接去执行,语法错误也只有运行过程中才能发现。一旦执行过程中出现错误,后续的代码就不能继续执行了。

一. 抓自己的包

  1. 思路:调用 req 的各个方法, 把得到的结果汇总到一个 StringBuilder/StringBuffer 中, 统一返回到页面上
  2. 为什么换行用< br> 而不是\n:该内容是在浏览器上按照 html 的方式来展示的、
    /n是字符的换行符,而非HTML的换行符
  3. 关于乱码问题:字符集不匹配,IDEA多是使用utf8编码,浏览器则默认跟着操作系统走,Windows操作系统的编码位gbk
  4. 注意:实际开发中,我们多用 fidder 进行抓包
@WebServlet("/request")
public class RequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	//必要的,显式告诉浏览器, 你拿到的数据是 html
        resp.setContentType("text/html");

        StringBuilder respBody = new StringBuilder();
        respBody.append(req.getProtocol());
        respBody.append("<br>");
        respBody.append(req.getMethod());
        respBody.append("<br>");
        respBody.append(req.getRequestURI());
        respBody.append("<br>");
        respBody.append(req.getContextPath());
        respBody.append("<br>");
        respBody.append(req.getQueryString());
        respBody.append("<p>下面是枚举的</p>");

        Enumeration<String> headers = req.getHeaderNames();
        while (headers.hasMoreElements()){
            String header = headers.nextElement();
            respBody.append(header + ":" + req.getHeader(header));
            respBody.append("<br>");
        }

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

在这里插入图片描述

二、构造一个重定向的响应,让页面重定向到百度主页

  1. 方法一:setHeader() + setStatus()
    • 原理
      • 这段代码将会涉及两个请求,一个是req,一个是“访问百度主页”的请求。
      • 浏览器看到【302+location】字段,就知道要执行跳转操作了
    • location:用该属性描述重定向到哪个地方
    • 301 VS 302
      • 相同点:直观效果差不多,事实上3开头的效果都差不多
      • 不同点
        301 ----->永久重定向,以后一直重定向
        302 ----->临时重定向,以后可能不重定向了,或者重定向到其他地方
    • 永久重定向 VS 临时重定向:在浏览器上可能会有些不同,但这些不同的设计是设计者的初心,实际开发中程序员并不会刻意区分
      • 不同的浏览器对待永久重定向,首次访问后会搞一个缓存,后续直接访问缓存。
      • 如果是临时重定向,就是每次都去服务器那请求一下
@WebServlet("/trans")
public class ServletTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(302);
        resp.setHeader("location", "https://www.baidu.com");
    }
}
  1. 写法二:resp.sendRedirect(String location),做了写法一的两个代码的工作

三、让服务器返回一个html数据

  1. 关于字符编码问题
    • 修改原则:更改浏览器的编码方式
      因为 uft8 是更主流的编码方式,gbk只能表示简体中文,是无法表示其他例如方言的文字的
    • 如何查看并修改IDEA的字符集:setting ----> encoding
      在这里插入图片描述
    • 让浏览器更改字符集
      • 请求的字符集取决于页面,而 html 有声明字符集的部分。< meta charset = “UTF-8”>
      • 使用resp进行更改。要注意顺序,先header后body,因为一旦开始设置 body ,此时就相当于header和status都定性了,后续即使是修改了,也无法生效。
@WebServlet("/getHtml")
public class HTMLTest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("<div>你好</div>");
    }
}

四、表白墙

4.1 约定前后端数据

  1. 概念
    • 指进行前后端交互接口的约定,比如前端发送什么样的请求,后端返回什么样的响应
    • 前后端数据交互的格式可以随便约定,但双方一定要互相遵守
  2. 请求的格式:“路径是什么” 以及 “传来的数据格式是xml还是JSON”
  3. 响应的格式:返回的数据格式是什么,状态码是什么

4.2 前端代码

  1. 放前端页面:放到webapp目录下,可通过网络访问,如127.0.0.1:8080/test/messageWall.html
  2. 获取到输入框的内容:
    • 选中元素:使用querySelector()、querySelectorAll()方法,这些是由浏览器提供的API,可以用来获取到页面的元素。如 let button = document.querySelector(‘#submit’);
    • 确认行为
      • JS中,函数是可以像变量一样复制的,这里相当于是把这个函数定义出来后就赋值给button.onclick()
      • 触发时机:当按钮被点击时,触发该函数,相当于是个回调函数
button.onclick = function() {
	XXXXX
 }
  1. 构造js对象
    (1)js对象也是由{}构成的键值对(JSON)就是出自这里
    (2)关于引号的问题:key都是字符串类型,value则可以是任何类型,由于key必须是字符串,所以key这里的引号是可以省略的。但是省略之后,容易看不出原本是什么类型的了,所以最好还是加上。
let body = {                    let body = {//简化版本,该情况表示键值对和value是一样的
    "from": from,                   from,
    "to": to,                       to,
    "message": msg                  msg
};                             	};
  1. 构造标签

    • 创建标签:let rowDiv = document.createElement(‘div’); 创建一个div标签
    • 给该标签设置一个类:rowDiv.className = ‘row message’;
    • 往标签里构造内容:rowDiv.innerHTML = from + ’ 对 ’ + to + ’ 说: ’ + msg;
    • 把该标签放到其他标签之后:containerDiv.appendChild(rowDiv);把该变量放到containerDiv这个对象的末尾
  2. 前后端交互:、ajax方法会更具输入的参数,构造出http请求并发给服务器、但原生的API比较难用,我们一般使用JQuery封装过后的API

    • 导入JQuery依赖
      • 搜索【JQuery cdn】,把< scriot>整个标签赋值过来即可,如< script src=“https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js”>

      • 前端加载某个第三方库的方式很简单,直接把库对应的网络地址加进来即可

    • success: function(body):这个body参数实际上包含了从服务器返回的响应数据。当前端成功接收到响应时调用这个函数。
    • JS对象和JSON对象互转 :JS对象虽然格式上和JSON非常相似,但是仍然是两个不同的东西
      • JS对象 —> JSON字符串:JSON,stringify()
      • JSON字符串 —> JS对象:JSON.parse()
    • JQuery的自动转换问题
      • JQuery 见到响应中的 application/json , 就会自动的把响应转换成 js 对象数组
      • 故此时的body 是 js 对象数组,而不是 json 字符串了。我们也就可以直接按照数组的方式来操作 body,,每个元素都是 js 对象
    • 关于url的值:相对路径方式比较常见,因为后续修改 contextPath 比较方便,可以减少耦合
      • 绝对路径写法:以“/”开头,如:‘/test/massage’
      • 相对路径写法:不以“/”开头,如:‘massage’。相对路径的基准是当前html所在的路径。当前html的路径是:“test/messageWall.html”
//发送一个HTTP请求
 $.ajax({

});
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>

<script>
    let containerDiv = document.querySelector('.container');
    let inputs = document.querySelectorAll('input');
    let button = document.querySelector('#submit');
    button.onclick = function() {
        // 1. 获取到三个输入框的内容
        let from = inputs[0].value;
        let to = inputs[1].value;
        let msg = inputs[2].value;
        if (from == '' || to == '' || msg == '') {
            return;
        }
        // 2. 构造新 div
        //相当于<div></div>
        let rowDiv = document.createElement('div');
        //相当于<div className = 'row message></div>
        rowDiv.className = 'row message';
        //相当于<div className = 'row message>构造的内容</div>
        rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
        //让创建出来的<div>加入到页面中
        containerDiv.appendChild(rowDiv);
        // 3. 清空之前的输入框内容
        for (let input of inputs) {
            input.value = '';
        }

        //4. 把用户输入的数据发送给服务器
        let body = {
            "from": from,
            "to": to,
            "message": msg
        };

        $.ajax({
            type: 'post',
            url: 'message',
            contentType: 'application/json; charset=utf8',
            data: JSON.stringify(body),
            success: function(body){
            //这里是把返回的结果打印到了前端的控制台处
                console.log(body);
            }
        });
    }

    $.ajax({
        type: 'get',
        url: 'message',
        success: function(body){
            let container = document.querySelector('.container');

            for (let i = 0; i < body.length; i++){
                let message = body[i];
                let div = document.createElement('div');
                div.className = 'row';
                div.innerHTML = message.from + " 对 " + message.to + 
                    " 说:" + message.message;
                container.appendChild(div);
            }
        }
    })

</script>

4.3 后端代码

  1. 引入Jackson依赖
  2. 把数据存储在服务器中
    • 内存
      • 创建一个ArrayList,把数据都存到这个顺序表中。当把List/数组转成JSON时,Jackson会自动将其整理成JSON数组,里面的每个元素也会被转换成JSON对象
      • 注意,此处是把数据保存到内存中,一旦重启服务器,内存数据就无了。
    • 数据库:把数据保存到数据库中,实现持久化保存
class Message{
    public String from;
    public String to;
    public String message;

    @Override
    public String toString() {
        return super.toString();
    }
}

@WebServlet("/message")
public class MessageWall extends HttpServlet {
    private ObjectMapper objectMapper = new ObjectMapper();
    private List<Message> messageList = new ArrayList<>();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String respJson = objectMapper.writeValueAsString(messageList);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respJson);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        messageList.add(message);
        System.out.println("服务器收到message:" + message);
        resp.setStatus(200);
        resp.getWriter().write("ok");
    }
}

4.4 保存在数据库的版本

  1. 引入数据库的依赖:之前是直接下载Mysql驱动包,现在也可以直接使用Maven进行管理
  2. 创建数据库和数据表
  3. 通过JDBC代码来操作数据库
@WebServlet("/messageWall")
public class MessageServlet extends HttpServlet {
    ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        try {
            add(message);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        System.out.println("服务器收到message:" + message);
        resp.setStatus(200);
        resp.getWriter().write("ok");
    }
    private void add(Message message) throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");

        Connection connection = dataSource.getConnection();
        String sql = "insert into message values(?, ?, ?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, message.from);
        statement.setString(2, message.to);
        statement.setString(3, message.message);
        statement.executeUpdate();

        statement.close();
        connection.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Message> messageList = null;
        try {
            messageList = load();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        resp.setContentType("application/json");
        String ret = objectMapper.writeValueAsString(messageList);
        resp.getWriter().write(ret);
    }

    public List<Message> load() throws SQLException {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/test?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");

        Connection connection = dataSource.getConnection();
        String sql = "select * from message";
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet resultSet = statement.executeQuery();
        List<Message> messageList = new ArrayList<>();
        while (resultSet.next()){
            Message message = new Message();
            message.from = resultSet.getString("from_user");
            message.to = resultSet.getString("to_user");
            message.message = resultSet.getString("message");
            messageList.add(message);
        }

        resultSet.close();
        statement.close();
        connection.close();
        return messageList;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/590018.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【学习vue 3.x】(二)组件应用及单文件组件

文章目录 章节介绍本章学习目标学习前的准备工作Vue.js文件下载地址 组件的概念及组件的基本使用方式组件的概念组件的命名方式与规范根组件局部组件与全局组件 组件之间是如何进行互相通信的父子通信父子通信需要注意的点 组件的属性与事件是如何进行处理的组件的属性与事件 组…

软件测试(实验五)——Jmeter的使用

目录 实验目的 一、使用JMeter演示取样器、监听器、配置元件、断言的使用&#xff1b; 1、取样器 2、监听器 3、配置元件的使用 ① 用户定义的变量 ②HTTP信息头管理器 ③HTTP请求默认值 ④CSV数据文件设置 4、断言 ①响应断言 ②JSON断言 ③断言持续时间 二、使用…

C语言之位操作符:<<、>>、、|、^、~,以及原码反码补码和例题详解

目录 前言 一、原码、反码、补码 二、移位操作符 三、位操作符&#xff1a;&、|、^、~ 四、经典例题分析&#xff1a; 总结 前言 本文将详细介绍C语言中左移操作符<<&#xff0c;右移操作符>>&#xff0c;按位与&&#xff0c;按位或|&#xff0c;按位异或^…

【QT学习】14补充,使用线程制作绘图工具

思路&#xff1a; 结果&#xff1a; 点击刷新图片&#xff0c;自动绘制一个六点连接图 线程类的属性 线程类的函数实现 void MyThread::drawImage(){//Qimage设备QImage image(600,600,QImage::Format_ARGB32);//画家QPainter p(&image);//画笔&#xff0c;画刷QPen pen;pe…

进位计数制

目录 前言 最古老的计数方法 十进制数 推广:r 进制计数法 任意进制->十进制 二进制<->八进制,十六进制 十进制->任意进制 真值和机器数 总结: 前言 本篇文章我们正式进入第二章:数据的表示和运算,通过第一章的学习我们知道了现代计算机的结构 那数据如何…

基于php+mysql+html图书管理系统(含实训报告)

博主介绍&#xff1a; 大家好&#xff0c;本人精通Java、Python、Php、C#、C、C编程语言&#xff0c;同时也熟练掌握微信小程序、Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我有丰富的成品Java、Python、C#毕设项目经验&#xff0c;能够为学生提供各类…

自然语言处理 (NLP) 中的迁移学习

--懂王 在大数据高速发展的时代&#xff0c;AI的发展日新月异&#xff0c;充满挑战的迎接未来。 自然语言处理 (NLP) 中的迁移学习: 迁移学习在 NLP 中越来越受欢迎&#xff0c;特别是在数据稀缺的情况下。如何有效地利用预训练的语言模型&#xff0c;并将其迁移到新的任务和领…

kubectl_入门_service详解

Service 我们知道 Pod 的生命周期是有限的。可以用 ReplicaSet 和Deployment 来动态的创建和销毁 Pod&#xff0c;每个 Pod 都有自己的 IP 地址&#xff0c;但是如果 Pod 重建了的话那么他的 IP 很有可能也就变化了。 这就会带来一个问题&#xff1a;比如我们有一些后端的 Po…

基于Springboot的教学资源共享平台(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的教学资源共享平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

【Cpp】类和对象#构造函数 析构函数

标题&#xff1a;【Cpp】类和对象#构造函数 析构函数 水墨不写bug &#xff08;图片来源于网络&#xff09; 正文开始&#xff1a; &#xff08;一&#xff09;构造函数 构造函数是特殊的成员函数&#xff0c;需要注意的是&#xff0c;构造函数虽然名称叫构造&#xff0c;但…

nginx变量自定义日志收集

内置变量 $remote_addr&#xff1b;存放了客户端的地址&#xff0c;注意是客户端的公网IP&#xff0c;也就是一家人访问一个网站&#xff0c;则会显示为路由器的公网IP。 $args&#xff1b;变量中存放了URL中的指令 [rootlocalhost conf.d]# cat pc.conf server {listen 80;se…

数组的扩容与缩容

数组的扩容与缩容 文章目录 数组的扩容与缩容数组的扩容内存分析 数组的缩容内存分析内存分析 数组的扩容 数组扩容是指当原有数组的空间不足以容纳更多的元素时&#xff0c;创建一个新的、长度更大的数组&#xff0c;并将原数组中的元素复制到新数组中&#xff0c;然后更新原…

C++入门第二节--关键字、命名空间、输入输出

点赞关注不迷路&#xff01;本节涉及c入门关键字、命名空间、输入输出... 1. C关键字 C总计63个关键字&#xff0c;C语言32个关键字 asmdoifreturntrycontinueautodoubleinlineshorttypedefforbooldynamic_castintsignedtypeidpublicbreakelselongsizeoftypenamethrowcaseen…

如何完全卸载QT

第一步&#xff0c;用QT自带的软件卸载QT 第二步&#xff0c;卸载下面路径的所有QT配置 C:用户/(你的用户)/AppData/Local/目录下所有与Qt相关内容 C:用户/(你的用户)/AppData/Local/Temp/所有与Qt相关内容 C:用户/(你的用户)/AppData/Roaming/所有与Qt相关内容

C 深入指针(2)

目录 1 野指针 1.1 成因 1.2 如何规避野指针 2 assert 断言 2.1 用法 2.2 assert 的优点 2.1 assert 的缺点 3 小注解 3.1 Debug 和 Release 1 野指针 【概念】&#xff1a; 野指针就是指针指向的位置是不可知的&#xff08;随机的、不正确的、没有明确限制的&#…

场景文本检测识别学习 day06(Vi-Transformer论文精读、MAE论文阅读)

Vi-Transformer论文精读 在NLP领域&#xff0c;基于注意力的Transformer模型使用的非常广泛&#xff0c;但是在计算机视觉领域&#xff0c;注意力更多是和CNN一起使用&#xff0c;或者是单纯将CNN的卷积替换成注意力&#xff0c;但是整体的CNN 架构没有发生改变VIT说明&#x…

与 Apollo 共创生态:企业解决方案Apollo X 9.0,七载同舟,携手远航,视频简说

目录 介绍背景方案与项目Apollo 开源项目Apollo X 企业解决方案落地因素助力企业落地流程 预置套件需求定义功能定义场景用例融合技术面向园区功能安全Cyber RT企业硬件套件 开发工具链研发迭代范式协同研发工具链标定工具地图工具仿真平台数据闭环 企业合作模式合作方式 共创计…

[初阶数据结构】时间复杂度与空间复杂度

前言 &#x1f4da;作者简介&#xff1a;爱编程的小马&#xff0c;正在学习C/C&#xff0c;Linux及MySQL。 &#x1f4da;本文收录于初阶数据结构系列&#xff0c;本专栏主要是针对时间、空间复杂度&#xff0c;顺序表和链表、栈和队列、二叉树以及各类排序算法&#xff0c;持续…

nuxt3使用记录六:禁用莫名其妙的Tailwind CSS(html文件大大减小)

发现这个问题是因为&#xff0c;今天我突然很好奇&#xff0c;我发现之前构建的自动产生的200.html和404.html足足290k&#xff0c;怎么这么大呢&#xff1f;不是很占用我带宽&#xff1f; 一个啥东西都没有的静态页面&#xff0c;凭啥这么大&#xff01;所以我就想着手动把他…

ICode国际青少年编程竞赛- Python-1级训练场-基础训练2

ICode国际青少年编程竞赛- Python-1级训练场-基础训练2 1、 a 4 # 变量a存储的数字是4 Dev.step(a) # 因为变量a的值是4&#xff0c;所以Dev.step(a)就相当于Dev.step(4)2、 a 1 # 变量a的值为1 for i in range(4):Dev.step(a)Dev.turnLeft()a a 1 # 变量a的值变为…