今天学习的主要内容是在IntelliJ IDEA开发环境中,通过部署Tomcat服务器并连接MySQL数据库,实现了一个完整的留言板系统。这个项目涵盖了前后端开发的全流程,具体包括以下关键环节:

  1. 开发环境搭建
  • 使用IntelliJ IDEA Ultimate版(2023.3)作为开发工具
  • 配置Tomcat 9.0服务器
  • 建立MySQL 8.0数据库连接
  1. 前端开发
  • 采用JSP+HTML+CSS技术栈
  • 设计留言板界面包含:
    • 留言展示区域(展示已有留言列表)
    • 留言表单(包含用户名、留言内容输入框)
    • 提交按钮
  1. 后端开发
  • 使用Java Servlet处理HTTP请求
  • 实现的主要功能点:
    • GET请求处理:从数据库查询留言列表并返回给前端
    • POST请求处理:接收前端提交的留言数据并存入数据库
  • 采用JDBC连接池技术实现数据库操作
  1. 数据库设计
  • 创建message表,包含字段:
    • id(主键,自增)
    • username(varchar,留言者姓名)
    • content(text,留言内容)
    • create_time(timestamp,留言时间)
  1. 功能实现细节
  • 查看功能:
    • 通过SELECT语句查询所有留言
    • 按时间倒序排列显示
    • 将查询结果封装为List<Message>对象返回前端
  • 保存功能:
    • 接收前端表单提交的username和content参数
    • 执行INSERT语句将数据存入数据库
    • 添加事务处理确保数据一致性
  1. 测试验证
  • 通过浏览器访问留言板页面
  • 测试留言提交和展示功能
  • 验证数据库记录的增删改查操作

这个项目虽然基础,但完整实现了从用户界面到数据存储的整个流程,对于理解Web应用开发的基本原理和流程有很好的实践意义。

代码如下:

import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;import javax.sql.DataSource;public class DButil {public static HikariDataSource getDataSource() {HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/javawebday1");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("admin123");return dataSource;}
}import java.time.LocalDateTime;public class message {private Integer id;private String nickname;private String content;private String ip;private LocalDateTime mtime;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getNickname() {return nickname;}public void setNickname(String nickname) {this.nickname = nickname;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public LocalDateTime getMtime() {return mtime;}public void setMtime(LocalDateTime mtime) {this.mtime = mtime;}
}import com.coder.message;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;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.io.PrintWriter;
import java.sql.SQLException;
import java.util.List;@WebServlet("/view")
public class ViewMessageBoardServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");PrintWriter out = resp.getWriter();//查询数据库HikariDataSource dataSource = new HikariDataSource();dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/szb");dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUsername("root");dataSource.setPassword("admin123");QueryRunner runner = new QueryRunner(dataSource);String sql = "select id,nickname,content,ip,mtime from message order by mtime desc";try {List<message> list = runner.query(sql,new BeanListHandler<message>(message.class));StringBuffer sbf = new StringBuffer();sbf.append("<table width = '800' border = '1'> align = ‘center'").append("<tr><td>序号</td>").append("<td>昵称</td>").append("<td>留言</td>").append("<td>IP</td>").append("<td>时间</td></td>");int index = 1;for (message message : list) {sbf.append("<tr>").append("<td>").append(index++).append("</td>").append("<td>").append(message.getNickname()).append("</td>").append("<td>").append(message.getContent()).append("</td>").append("<td>").append(message.getIp()).append("</td>").append("<td>").append(message.getMtime()).append("</td>").append("</tr>");}sbf.append("</table>");out.println("<a href = 'buy.html'>继续留言</a>");out.println(sbf);} catch (SQLException e) {throw new RuntimeException(e);}}
}import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbutils.QueryRunner;
import util.DButil;import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.time.LocalDateTime;/*** @author MSI-NB* @date 2025/8/6 22:41*/
@WebServlet(name = "messageBoardServlet", urlPatterns = "/x")
public class messageBoardServlet extends HttpServlet {private static final long serialVersionUID = 1L;/*** @see HttpServlet#HttpServlet()*/public messageBoardServlet() {super();}/*** @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)*/protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");}/*** @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 设置请求编码request.setCharacterEncoding("UTF-8");response.setContentType("text/html");response.setCharacterEncoding("UTF-8");String nickname = request.getParameter("nickname");String content = request.getParameter("content");String ip = request.getRemoteAddr();PrintWriter out = response.getWriter();//        out.println("您的名称是:" + nickname + "<br>");
//        out.println("您的留言是:" + content + "<br>");QueryRunner runner = new QueryRunner(DButil.getDataSource());String sql = "insert into message(nickname,content,ip,mtime) values(default,?,?,?,?)";try {int update = runner.update(sql,nickname,content,ip, LocalDateTime.now());System.out.println(update>0?"留言成功":"留言失败");} catch (SQLException e) {e.printStackTrace();}}
}

message.html:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="x" method="post"><div>昵称:<input type="text" name="nickName"></div><div>留言:<textarea name="content"></textarea></div><div><button type="submit">提交留言</button></div></form>
</body>
</html>

通过实践,我总结出几个重要的经验教训:

  1. 获取客户端 IP 时,应该使用 String ip = req.getRemoteAddr(),而不是 getParameter 方法。当数据库表 buy_recorders 的 ip 字段设为 NOT NULL 时,插入 null 值会直接引发 SQL 异常。

  2. 即使 ip 字段允许为 null,在查询时使用 where ip = null 也会导致语法错误,正确的写法应该是 where ip is null,否则同样会触发 500 错误。

  3. 在开发留言板功能时,我直接复制了之前的代码,但忘记修改新数据库的 SQL 语句,这又导致了 500 错误。这个疏忽让我意识到复制代码时需要格外谨慎。

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

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

相关文章

【计算机网络 | 第3篇】物理媒介

文章目录物理媒介介绍与物理媒体的分类&#x1f95d;成本考量引导型传输媒体&#x1f34b;引导型传输媒体&#xff1a;双绞线&#x1f34b;‍&#x1f7e9;双绞线类别双绞线的发展历程双绞线的物理限制引导型传输媒体&#xff1a;同轴电缆&#x1f34b;‍&#x1f7e9;结构组成…

golang的切片

切片 为什么需要切片 用于元素的个数不确定&#xff0c;所以无法通过数组的形式来进行统计。此时就需要切片 切片&#xff0c;也因此可以粗略地理解为动态数组数组的长度不能用变量来确定&#xff0c;这时候切片slice也就派上用场了 切片地基本介绍 切片的英文是slice切片是数组…

在labview中实现视频播放

这里分享一个迅雷的视频播放控件APlayer&#xff0c;非常的好用。具体操作步骤如下&#xff1a; 1.下载控件: 首先下载http://aplayer.open.xunlei.com/codecs.zip&#xff0c;将codecs文件解压后打开&#xff0c;按快捷键contrlA,随后contrlc复制里面所有的文件&#xff1b;…

ubuntu 22.04 使用yaml文件 修改静态ip

前提&#xff1a; 启动服务 sudo systemctl start systemd-networkd 设置开机自启 sudo systemctl enable systemd-networkd 检查状态&#xff08;确保显示 active (running)&#xff09; sudo systemctl status systemd-networkd 若想停止&#xff1a; 停止当前运行的服务 sud…

闸机控制系统从设计到实现全解析:第 4 篇:Redis 缓存与分布式锁实现

第 4 篇&#xff1a;Redis 缓存与分布式锁实现 一、Redis 在系统中的核心作用票证信息缓存&#xff1a;将高频访问的票证数据&#xff08;如状态、有效期&#xff09;缓存至 Redis&#xff0c;减少数据库查询&#xff0c;提升验证响应速度。分布式锁&#xff1a;在高并发场景下…

北京天津唐山廊坊沧州打捞日记

北京天津唐山廊坊沧州打捞日记 打捞搜蚯蚓疏通 北京&#xff1a;护城河畔的情谊打捞 清晨&#xff0c;北京的护城河在朝阳的映照下泛着微光。我接到一位年轻小伙的电话&#xff0c;声音中满是焦急。原来&#xff0c;他与女友在河边约会时&#xff0c;不小心将女友送他的定情玉佩…

全志刷机工具:PhoenixSuit-全志芯片处理器-刷机工具安装包及最详细使用教程指南

全志刷机工具&#xff1a;PhoenixSuit-全志芯片处理器刷机工具安装包及最详细使用教程指南&#xff0c;此文章主要是分享机顶盒、电视盒子&#xff0c;全志芯片盒子&#xff08;其中包含全志处理器、全志芯片、全志CPU等等&#xff09;的刷机工具、刷机工具安装教程以及如何使用…

浅谈 VM 桥接模式:让虚拟机像真实电脑一样接入网络

在虚拟化环境中&#xff0c;虚拟机&#xff08;Virtual Machine, VM&#xff09;与外部网络之间的通信方式有多种&#xff0c;比如 NAT 模式、Host-Only 模式、桥接模式&#xff08;Bridged Networking&#xff09; 等。其中&#xff0c;桥接模式是最接近“真实物理机”网络行为…

计算机视觉(1)-图像采集设备选型全景表(工业 + 医疗 + 车载)

图像采集设备选型全景表&#xff08;工业 医疗 车载&#xff09;一份面向工程师的“场景—设备—协议”速查表1 工业 & 医疗 & 通用场景应用场景主流设备形态接口 / 协议典型性能突出优势致命短板动态范围工业检测AOI / 量测 / 缺陷工业相机 采集卡Camera Link HSCo…

计算机视觉(3)深度学习模型部署平台技术选型与全栈实践指南

一、部署平台概述与分类 深度学习模型部署平台的分类需兼顾技术特性与应用场景的适配性&#xff0c;基于“技术定位-场景适配”双维度分类法&#xff0c;可将其划分为通用开源框架、云厂商服务及专用边缘工具三大类&#xff0c;各类别在设计目标、核心能力与场景覆盖上呈现显著…

Scratch编程:枪战游戏(附源码)

&#x1f3ae; 操作说明 W / A / S / D 或 方向键&#xff1a;移动 C&#xff1a;滑铲 空格键&#xff1a;取消滑铲 鼠标点击&#xff1a;开火 数字键 1 / 2 / 3 / 4&#xff1a;切换武器 G&#xff1a;快速使用道具 F&#xff1a;近战攻击 Q&#xff1a;瞄准 / 使用技能…

应急响应复现

一、前言&#xff1a;当企业发生黑客入侵、系统崩溃或其它影响业务正常运行的安全事件时&#xff0c;急需第一时间进行处理&#xff0c;使企业的网络信息系统在最短时间内恢复正常工作&#xff0c;进一步查找入侵来源&#xff0c;还原入侵事故过程&#xff0c;同时给出解决方案…

分布式事务Seata TCC模式篇

介绍 ​ 官网: https://seata.apache.org/zh-cn/docs/user/mode/tcc ​ 回顾Seata AT 模式基于 支持本地 ACID 事务 的 关系型数据库&#xff0c;如下&#xff1a; 一阶段 prepare 行为&#xff1a;在本地事务中&#xff0c;一并提交业务数据更新和相应回滚日志记录。二阶段 c…

Day37--动态规划--52. 携带研究材料(卡码网),518. 零钱兑换 II,377. 组合总和 Ⅳ,57. 爬楼梯(卡码网)

Day37–动态规划–52. 携带研究材料&#xff08;卡码网&#xff09;&#xff0c;518. 零钱兑换 II&#xff0c;377. 组合总和 Ⅳ&#xff0c;57. 爬楼梯&#xff08;卡码网&#xff09; 本文全部都是 ” 完全背包 “ 问题&#xff0c;从零到入坑&#xff0c;从入坑到爬出来。 本…

Linux文件操作

Linux文件Linux下的文件类型b 块设备文件---->存储类设备&#xff08;硬盘&#xff09;c 字符设备文件--->输入输出设备d 目录文件--->文件夹- 普通文件--> xxx.c xxx.h xxx.txt xxx.jpg xxx.mp4 a.outl 软链接文件-->快捷方式s 套接字文件-->网络通信p 管道…

Linux epoll 触发模式详解:LT vs ET

两种核心触发模式 1. 水平触发 (Level-Triggered, LT) 工作方式: 当文件描述符处于就绪状态时,epoll 会持续通知 只要状态未改变,每次调用 epoll_wait 都会返回该描述符 特点: c // 内核处理逻辑 (ep_send_events_proc) if (!(epi->event.events & EPOLLET)) { /…

STM32学习笔记6-TIM-2输出比较功能

第二部分&#xff0c;定时器的输出比较功能OC&#xff08;Output Compare&#xff09;输出比较输出比较可以通过比较CNT与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形每个高级定时器和通用定时器都拥有4…

MATLAB核心技巧:从入门到精通

一 1.数值 显示 格式 format style 设置 eg: pi format longE; or 2.清除指令 clc 清除命令行窗口 clear 清除工作区 cls 3.搜索路径设置 path(path,E:\ads\) or addpath 4.M文件 用户把要实现的命令写在一个以.m为扩展的文件中&#xff0c;然后由matlab系统进行解读…

AnyDesk远程工具免费版,v9.5.110绿色便携版,秒连远程桌面,剪贴板同步超实用

[软件名称]: AnyDesk远程工具免费版 [软件大小]: 7.5 MB [软件大小]: 夸克网盘 | 百度网盘 软件介绍 AnyDesk 让远程工作变得轻而易举。无论您身处办公室的另一端还是世界的另一侧&#xff0c;只需在设备上下载、安装并启动 AnyDesk.exe&#xff0c;即可轻松访问远程屏幕。…

AI: 给Gemini CLI配上“说明书”, 精通的GEMINI.md项目记忆

嘿&#xff0c;各位技术同好&#xff01;今天我们来聊一个能极大提升AI编程助手效率的酷炫功能——Google Gemini CLI 中的 GEMINI.md 文件。 在日常开发中&#xff0c;我们越来越依赖像 Gemini 这样的 AI 助手来帮我们写代码、调试 Bug 甚至重构项目。但大家是否遇到过这种情况…