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 {@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());}
}

在这里插入图片描述

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

  1. 方法一: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");}
}
  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 {@Overrideprotected 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 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 后端代码

  1. 引入Jackson依赖
  2. 把数据存储在服务器中
    • 内存
      • 创建一个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 保存在数据库的版本

  1. 引入数据库的依赖:之前是直接下载Mysql驱动包,现在也可以直接使用Maven进行管理
  2. 创建数据库和数据表
  3. 通过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;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

力扣hot100:101. 对称二叉树(双指针以不同方式递归)

LeetCode&#xff1a;101. 对称二叉树 看了第一个样例&#xff0c;很容易直接层序遍历看每一层的前后是否相同。但接下来这个样例告诉你&#xff0c;不能这样做。 层序遍历 仔细思考会发现&#xff0c;层序遍历不能看本结点&#xff0c;但是可以看儿子结点是否对称&#xf…

【JAVA进阶篇教学】第九篇:MyBatis-Plus用法介绍

博主打算从0-1讲解下java进阶篇教学&#xff0c;今天教学第九篇&#xff1a;MyBatis-Plus用法介绍。 在 MyBatis-Plus 3.5.0 中&#xff0c;LambdaQueryWrapper支持多种条件构造方式&#xff0c;除了等于&#xff08;eq&#xff09;、不等于&#xff08;ne&#xff09;、大于&a…

tomcat篇-windows 运行tomcat的startup.bat时,终端打印的中文显示为乱码

当运行Tomcat的startup.bat时&#xff0c;如果终端中中文显示为乱码&#xff0c;这通常是因为Tomcat使用的日志输出编码与Windows命令行默认的编码不匹配。针对这一问题&#xff0c;你可以尝试以下步骤来解决&#xff1a; 1、执行startup.bat&#xff0c;在输出的窗口右击&…

【MyBatis】深入解析MyBatis:高效操作数据库技术详解

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【MyBatis】深入解析MyBatis&#xff1a;高效操作数据库技术详解 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 动态SQL1. \<if>标签2. \<trim&…

Spring - 6 ( 9000 字 Spring 入门级教程 )

一&#xff1a; SpringBoot 配置文件 1.1 配置文件作用 配置文件通常是一个文本文件&#xff0c;其中包含了程序或系统的各种设置、选项和参数。比如C:\Users, C:\Windows 文件夹, 以及各种 .config, .xml 文件 配置文件主要是为了解决硬编码&#xff08;代码写死&#xff0…

专业渗透测试 Phpsploit-Framework(PSF)框架软件小白入门教程(一)

本系列课程&#xff0c;将重点讲解Phpsploit-Framework框架软件的基础使用&#xff01; 本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01; Phpsploit-Framework&#xff08;简称 PSF&#xff09;框架软件&#xff0c;是一款什么样的软件呢&#xff1f; Phpspl…

模拟实现memcpy,memmove,memset,memcmp

memcpy void * memcpy ( void * destination, const void * source, size_t num ); 使用注意事项&#xff1a; 从source的位置向后复制num个字节数据到destination所指向的内存位置中。 这个函数遇到如果源空间和⽬标空间出现重叠&#xff0c;就得使⽤memmove函数处理。 …

【Linux入门】基础开发工具

本篇博客整理了Linux&#xff08;centOS版本&#xff09;中基础开发工具的用途和用法&#xff0c;旨在透过开发工具的使用&#xff0c;帮助读者更好地理解可执行程序的编写、编译、运行等。 目录 一、软件包管理器 yum 1.软件的下载与安装 2.Linux应用商店&#xff1a;yum …

C#描述-计算机视觉OpenCV(4):图像分割

C#描述-计算机视觉OpenCV&#xff08;4&#xff09;&#xff1a;图像分割 前言用 GrabCut 算法分割图像实例展示 前言 本文中如果有什么没说明的地方&#xff0c;大概率在前文中描述过了。 C#描述-计算机视觉OpenCV&#xff08;1&#xff09;&#xff1a;基础操作 C#描述-计算…

VTK —— 二、教程五 - 通过鼠标事件与渲染交互(附完整源码)

代码效果 本代码编译运行均在如下链接文章生成的库执行成功&#xff0c;若无VTK库则请先参考如下链接编译vtk源码&#xff1a; VTK —— 一、Windows10下编译VTK源码&#xff0c;并用Vs2017代码测试&#xff08;附编译流程、附编译好的库、vtk测试源码&#xff09; 教程描述 本…

Unity类银河恶魔城学习记录15-3 p155 More example on audio effects

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili ​ AudioManager.cs using System.Collections; using System.Collections.…

XYCTF2024 RE Trustme 复现

但是只得到用户名 admin 法一&#xff1a;猜Sql注入&#xff0c;直接万能密码 法二&#xff1a;正常逆向 jadx中的AndroidManifest.xml有奇怪之处 怀疑有加壳&#xff0c;进ProxyApplication看看 大量安卓一代壳的特征 Android第一代壳加固原理及实现 - 知乎 GitHub - Huye…

基于双层优化的电动汽车优化调度研究(附matlab程序)

基于双层优化的电动汽车优化调度研究 0.代码链接 基于双层优化的电动汽车优化调度研究(matlab程序)资源-CSDN文库 1.简述 关键词&#xff1a;双层优化 选址定容 输配协同 时空优化 参考文档&#xff1a;《考虑大规模电动汽车接入电网的双层优化调度策略_胡文平》…

confluence 设置https代理

使用nginx反待confluence并开启https后&#xff0c;登录confluence会一直提示&#xff1a;scheme、proxyName、proxyPort设置错误。 解决办法&#xff1a; find / -name server.xmlvi /opt/atlassian/confluence/conf/server.xml HTTP反代配置 HTTPS反代配置

[leetcode] 61. 旋转链表

文章目录 题目描述解题方法遍历java代码复杂度分析 相似题目 题目描述 给你一个链表的头节点 head &#xff0c;旋转链表&#xff0c;将链表每个节点向右移动 k 个位置。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], k 2 输出&#xff1a;[4,5,1,2,3]示例 2&…

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习

ICode国际青少年编程竞赛- Python-1级训练场-for循环练习 1、 for i in range(3):Dev.step(4)Dev.turnLeft()2、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()3、 for i in range(3):Dev.step(2)Dev.turnRight()Dev.step(2)Dev.turnLeft()4、 for…

Deep learning Part Five RNN--24.4.29

接着上期&#xff0c;CBOW模型无法解决文章内容过长的单词预测的&#xff0c;那该如何解决呢&#xff1f; 除此之外&#xff0c;根据图中5-5的左图所示&#xff0c;在CBOW模型的中间层求单词向量的和&#xff0c;这时就会出现另一个问题的&#xff0c;那就是上下文的单词的顺序…

PC通过串口发送指令控制LED+串口中断

如何让单片机接收数据&#xff1f; 首先要打开SCON中的串行接收控制位REN。当REN1时为允许接收状态&#xff0c;可以接收信息。 因此令SCON 0x50&#xff1b; 怎么知道收到数据&#xff1f; 利用RI接收中断请求标志位。当串行接收到第8位结束时由内部硬件自动置为RI1&#…

机器人系统ros2-开发实践04-ROS2 中 tf2的定义及示例说明

1. what ros2 tf2 &#xff1f; tf2的全称是transform2&#xff0c;在ROS&#xff08;Robot Operating System&#xff09;中&#xff0c;它是专门用于处理和变换不同坐标系间位置和方向的库。这个名字来源于“transform”这个词&#xff0c;表示坐标变换&#xff0c;而“2”则…

【抽代复习笔记】17-群(十一):置换的练习题(1)

练习1&#xff1a;计算&#xff1a; 解&#xff1a; 解析&#xff1a;①左边的置换是1保持不变&#xff0c;2变成3&#xff0c;3变成4&#xff0c;4变成5&#xff0c;5变成2&#xff0c;因此可以简写为(2345)&#xff1b;右边的置换是2和5保持不变&#xff0c;1变成3&#xff…