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 如何处理错误
- 判断前端 or 后端问题:通过fidder抓包判断
- 如果抓包发现 ajax 的http请求根本没发出来,那大概率就是前端问题
- 如果ajax的http请求发了,且内容符合要求,那大概率是后端问题
- 处理前端问题:去浏览器的开发者工具上看,不要看VSCode里的前端代码,因为js代码都是被下载到浏览器后执行的
- F12或右键检查打开开发者工具,source部分表示了当前浏览器加载了哪些前端代码
- JS代码编译问题:JS代码在执行过程中,并不像Java有先编译的过程,而是直接去执行,语法错误也只有运行过程中才能发现。一旦执行过程中出现错误,后续的代码就不能继续执行了。
一. 抓自己的包
- 思路:调用 req 的各个方法, 把得到的结果汇总到一个 StringBuilder/StringBuffer 中, 统一返回到页面上
- 为什么换行用< br> 而不是\n:该内容是在浏览器上按照 html 的方式来展示的、
/n是字符的换行符,而非HTML的换行符 - 关于乱码问题:字符集不匹配,IDEA多是使用utf8编码,浏览器则默认跟着操作系统走,Windows操作系统的编码位gbk
- 注意:实际开发中,我们多用 fidder 进行抓包
@WebServlet("/request")
public class RequestServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//必要的,显式告诉浏览器, 你拿到的数据是 htmlresp.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());}
}
二、构造一个重定向的响应,让页面重定向到百度主页
- 方法一:setHeader() + setStatus()
- 原理:
- 这段代码将会涉及两个请求,一个是req,一个是“访问百度主页”的请求。
- 浏览器看到【302+location】字段,就知道要执行跳转操作了
- location:用该属性描述重定向到哪个地方
- 301 VS 302:
- 相同点:直观效果差不多,事实上3开头的效果都差不多
- 不同点:
301 ----->永久重定向,以后一直重定向
302 ----->临时重定向,以后可能不重定向了,或者重定向到其他地方
- 永久重定向 VS 临时重定向:在浏览器上可能会有些不同,但这些不同的设计是设计者的初心,实际开发中程序员并不会刻意区分
- 不同的浏览器对待永久重定向,首次访问后会搞一个缓存,后续直接访问缓存。
- 如果是临时重定向,就是每次都去服务器那请求一下
- 原理:
@WebServlet("/trans")
public class ServletTest extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setStatus(302);resp.setHeader("location", "https://www.baidu.com");}
}
- 写法二:resp.sendRedirect(String location),做了写法一的两个代码的工作
三、让服务器返回一个html数据
- 关于字符编码问题:
- 修改原则:更改浏览器的编码方式
因为 uft8 是更主流的编码方式,gbk只能表示简体中文,是无法表示其他例如方言的文字的 - 如何查看并修改IDEA的字符集:setting ----> encoding
- 让浏览器更改字符集:
- 请求的字符集取决于页面,而 html 有声明字符集的部分。< meta charset = “UTF-8”>
- 使用resp进行更改。要注意顺序,先header后body,因为一旦开始设置 body ,此时就相当于header和status都定性了,后续即使是修改了,也无法生效。
- 修改原则:更改浏览器的编码方式
@WebServlet("/getHtml")
public class HTMLTest extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("<div>你好</div>");}
}
四、表白墙
4.1 约定前后端数据
- 概念:
- 指进行前后端交互接口的约定,比如前端发送什么样的请求,后端返回什么样的响应
- 前后端数据交互的格式可以随便约定,但双方一定要互相遵守
- 请求的格式:“路径是什么” 以及 “传来的数据格式是xml还是JSON”
- 响应的格式:返回的数据格式是什么,状态码是什么
4.2 前端代码
- 放前端页面:放到webapp目录下,可通过网络访问,如127.0.0.1:8080/test/messageWall.html
- 获取到输入框的内容:
- 选中元素:使用querySelector()、querySelectorAll()方法,这些是由浏览器提供的API,可以用来获取到页面的元素。如 let button = document.querySelector(‘#submit’);
- 确认行为:
- JS中,函数是可以像变量一样复制的,这里相当于是把这个函数定义出来后就赋值给button.onclick()
- 触发时机:当按钮被点击时,触发该函数,相当于是个回调函数
button.onclick = function() {XXXXX}
- 构造js对象:
(1)js对象也是由{}构成的键值对(JSON)就是出自这里
(2)关于引号的问题:key都是字符串类型,value则可以是任何类型,由于key必须是字符串,所以key这里的引号是可以省略的。但是省略之后,容易看不出原本是什么类型的了,所以最好还是加上。
let body = { let body = {//简化版本,该情况表示键值对和value是一样的"from": from, from,"to": to, to,"message": msg msg
}; };
-
构造标签:
- 创建标签:let rowDiv = document.createElement(‘div’); 创建一个div标签
- 给该标签设置一个类:rowDiv.className = ‘row message’;
- 往标签里构造内容:rowDiv.innerHTML = from + ’ 对 ’ + to + ’ 说: ’ + msg;
- 把该标签放到其他标签之后:containerDiv.appendChild(rowDiv);把该变量放到containerDiv这个对象的末尾
-
前后端交互:、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”
- 导入JQuery依赖:
//发送一个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 class = '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 后端代码
- 引入Jackson依赖:
- 把数据存储在服务器中:
- 内存:
- 创建一个ArrayList,把数据都存到这个顺序表中。当把List/数组转成JSON时,Jackson会自动将其整理成JSON数组,里面的每个元素也会被转换成JSON对象
- 注意,此处是把数据保存到内存中,一旦重启服务器,内存数据就无了。
- 数据库:把数据保存到数据库中,实现持久化保存
- 内存:
class Message{public String from;public String to;public String message;@Overridepublic String toString() {return super.toString();}
}@WebServlet("/message")
public class MessageWall extends HttpServlet {private ObjectMapper objectMapper = new ObjectMapper();private List<Message> messageList = new ArrayList<>();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String respJson = objectMapper.writeValueAsString(messageList);resp.setContentType("application/json; charset=utf8");resp.getWriter().write(respJson);}@Overrideprotected 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 保存在数据库的版本
- 引入数据库的依赖:之前是直接下载Mysql驱动包,现在也可以直接使用Maven进行管理
- 创建数据库和数据表:
- 通过JDBC代码来操作数据库:
@WebServlet("/messageWall")
public class MessageServlet extends HttpServlet {ObjectMapper objectMapper = new ObjectMapper();@Overrideprotected 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();}@Overrideprotected 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;}
}
相关文章:

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

【JVM】垃圾回收机制(Garbage Collection)
目录 一、什么是垃圾回收? 二、为什么要有垃圾回收机制(GC)? 三、垃圾回收主要回收的内存区域 四、死亡对象的判断算法 a)引用计数算法 b)可达性分析算法 五、垃圾回收算法 a)标记-清除…...
C++中的priority_queue模拟实现
目录 priority_queue模拟实现 priority_queue类定义 priority_queue构造函数 priority_queue类push()函数 priority_queue类pop()函数 priority_queue类size()函数 priority_queue类empty()函数 priority_queue类top()函数 仿函数与priority_queue类模拟实现 仿函数 …...
【Kafka】1.Kafka核心概念、应用场景、常见问题及异常
Kafka 是一个分布式流处理平台,最初由 LinkedIn 开发,后成为 Apache 软件基金会的顶级项目。 它主要用于构建实时数据管道和流式应用程序。它能够高效地处理高吞吐量的数据,并支持消息发布和订阅模型。Kafka 的主要用途包括实时分析、事件源、…...
LTE的EARFCN和band之间的对应关系
一、通过EARFCN查询对应band 工作中经常遇到只知道EARFCN而需要计算band的情况,因此查了相关协议,找到了他们之间的对应关系,可以直接查表,非常方便。 具体见: 3GPP TS 36.101 5.7.3 Carrier frequency and EAR…...

解决问题:Docker证书到期(Error grabbing logs: rpc error: code = Unknown)导致无法查看日志
问题描述 Docker查看日志时portainer报错信息如下: Error grabbing logs: rpc error: code Unknown desc warning: incomplete log stream. some logs could not be retrieved for the following reasons: node klf9fdsjjt5tb0w4hxgr4s231 is not available报错…...
【C语言】预处理器
我们在开始编写一份程序的时候,从键盘录入的第一行代码: #include <stdio.h>这里就使用了预处理,引入头文件。 C预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C预处理器只不过是一…...
QtConcurrent::run操作界面ui的注意事项(2)
前面的“QtConcurrent::run操作界面ui的注意事项(1)”,末尾说了跨线程的问题,引出了Qt千好万好,就是跨线程不好。下面是认为的最简单的解决办法:使用QMetaObject::invokeMethod(相比较信号-槽&a…...

黑马程序员HarmonyOS4+NEXT星河版入门到企业级实战教程笔记
HarmonyOS NEXT是纯血鸿蒙,鸿蒙原生应用,彻底摆脱安卓 本课程是基于harmony os4的,与next仅部分api有区别 套件 语言&框架 harmony os design ArkTs 语言 ArkUI 提供各种组件 ArkCompiler 方舟编译器 开发&测试 DevEco Studio 开发…...

嵌入式全栈开发学习笔记---C语言笔试复习大全13(编程题9~16)
目录 9.查找字符数组中字符位置(输入hello e 输出2); 10、查找字符数组中字符串的位置(输入hello ll 输出3); 11、字符数组中在指定位置插入字符;(输入hello 3 a 输出heallo…...

https网站安全证书的作用与免费申请办法
HTTPS网站安全证书,也称为SSL证书,网站通过申请SSL证书将http协议升级到https协议 HTTPS网站安全证书的作用 1 增强用户信任:未使用https协议的网站,用户访问时浏览器会有“不安全”弹窗提示 2 提升SEO排名:搜索引擎…...

自动化测试再升级,大模型与软件测试相结合
近年来,软件行业一直在迅速发展,为了保证软件质量和提高效率,软件测试领域也在不断演进。如今,大模型技术的崛起为软件测试带来了前所未有的智能化浪潮。 软件测试一直是确保软件质量的关键环节,但传统的手动测试方法存…...
centos7 基础命令
一、基础信息: 查看IP地址: ip add 重启网络服务: service network restart 查看网卡配置: cat /etc/sysconfig/network-scripts/ifcfg-ens33 启动网卡: ifup ens33 查看内存: free -m 查看CPU: cat /proc/cpuin…...
【设计模式】之单例模式
系列文章目录 【设计模式】之责任链模式【设计模式】之策略模式【设计模式】之模板方法模式 文章目录 系列文章目录 前言 一、什么是单例模式 二、如何使用单例模式 1.单线程使用 2.多线程使用(一) 3.多线程使用(二) 4.多线程使用…...

3d模型实体显示有隐藏黑线?---模大狮模型网
在3D建模和设计领域,细节决定成败。然而,在处理3D模型时,可能会遇到模型实体上出现隐藏黑线的问题。这些黑线可能影响模型的视觉质量和呈现效果。因此,了解并解决这些隐藏黑线的问题至关重要。本文将探讨隐藏黑线出现的原因&#…...

共享购:全新消费模式的探索与实践
在消费模式日益创新的今天,共享购模式以其独特的消费与收益双重机制,吸引了众多消费者的目光。这一模式不仅为消费者带来了全新的购物体验,也为商家和平台带来了可观的收益。 一、会员体系:共享购的基石 在共享购模式下ÿ…...

Java集合 总结篇(全)
Java集合 集合底层框架总结 List 代表的有序,可重复的集合。 ArrayList -- 数组 -- 把他想象成C中的Vector就可以,当数组空间不够的时候,会自动扩容。 -- 线程不安全 LinkedList -- 双向链表 -- 可以将他理解成一个链表,不支持…...
Dubbo分层架构深度解析
引言 Dubbo作为一款备受欢迎的高性能、轻量级的Java RPC框架,在现代分布式系统中扮演着至关重要的角色。随着互联网行业的快速发展,服务间的通信变得越来越频繁,这也使得对于高效、可靠的远程通信方案的需求变得愈发迫切。在这样的背景下&am…...
LocalDate 数据库不兼容问题,因为LocalDate 是 long 类型的
我今天遇到一报错: SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession316f9272] was not registered for synchronization because synchronization is not active JDBC Connection [HikariProxyConnection2127597288 wrapping com.mysql.cj.jdbc…...

RVM(相关向量机)、CNN_RVM(卷积神经网络结合相关向量机)、RVM-Adaboost(相关向量机结合Adaboost)
当我们谈到RVM(Relevance Vector Machine,相关向量机)、CNN_RVM(卷积神经网络结合相关向量机)以及RVM-Adaboost(相关向量机结合AdaBoost算法)时,每种模型都有其独特的原理和结构。以…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

Golang——9、反射和文件操作
反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一:使用Read()读取文件2.3、方式二:bufio读取文件2.4、方式三:os.ReadFile读取2.5、写…...

数学建模-滑翔伞伞翼面积的设计,运动状态计算和优化 !
我们考虑滑翔伞的伞翼面积设计问题以及运动状态描述。滑翔伞的性能主要取决于伞翼面积、气动特性以及飞行员的重量。我们的目标是建立数学模型来描述滑翔伞的运动状态,并优化伞翼面积的设计。 一、问题分析 滑翔伞在飞行过程中受到重力、升力和阻力的作用。升力和阻力与伞翼面…...