• 【JavaWeb】-- Servlet获取网页数据并传入到数据库


    Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。

    web获取参数到数据库的原理:

    Web(用户)首先请求http页面,web服务器对其响应显示页面;

    用户点击表单提交按钮,调用(request)服务器端的add(表单中定义的action),add调用java类;

    java类中包括获取用户发送的数据操作、调用DAO中的方法添加到数据库、控制台打印。

    下面使用idea2022企业版+mysql8。


    代码实现

    下面以以下表格为题示例。

     

    一、创建数据库表

    1. CREATE TABLE 't_fruit' (
    2. 'fid' INT(11) NOT NULL AUTO_INCREMENT,
    3. 'fname' VARCHAR(20) NOT NULL,
    4. 'price' INT(11) DEFAULT NULL,
    5. 'fcount' INT(11) DEFAULT NULL,
    6. 'remark' VARCHAR(50) DEFAULT NULL,
    7. PRIMARY KEY ('fid')
    8. ) ENGINE=INNODB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;

    二、实现操作数据库

    1、加载驱动

    创建lib文件,将驱动文件复制进去并将文件添加为库。

     2、DAO

    使用DAO对数据库操作。

    文件结构:

     BaseDAO类

    其中,URL   3306/ 后面为数据库名字;

    USER 为用户名;

    PWD为密码;

    注意修改!

    1. package com.fruit.dao.base;
    2. import java.lang.reflect.Field;
    3. import java.lang.reflect.ParameterizedType;
    4. import java.lang.reflect.Type;
    5. import java.sql.*;
    6. import java.util.ArrayList;
    7. import java.util.List;
    8. public abstract class BaseDAO {
    9. public final String DRIVER = "com.mysql.jdbc.Driver" ;
    10. public final String URL = "jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
    11. public final String USER = "root";
    12. public final String PWD = "ad" ;
    13. protected Connection conn ;
    14. protected PreparedStatement psmt ;
    15. protected ResultSet rs ;
    16. //T的Class对象
    17. private Class entityClass ;
    18. public BaseDAO(){
    19. //getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
    20. //那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
    21. //因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
    22. //所以getGenericSuperclass()获取到的是BaseDAO的Class
    23. Type genericType = getClass().getGenericSuperclass();
    24. //ParameterizedType 参数化类型
    25. Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
    26. //获取到的中的T的真实的类型
    27. Type actualType = actualTypeArguments[0];
    28. try {
    29. entityClass = Class.forName(actualType.getTypeName());
    30. } catch (ClassNotFoundException e) {
    31. e.printStackTrace();
    32. }
    33. }
    34. protected Connection getConn(){
    35. try {
    36. //1.加载驱动
    37. Class.forName(DRIVER);
    38. //2.通过驱动管理器获取连接对象
    39. return DriverManager.getConnection(URL, USER, PWD);
    40. } catch (ClassNotFoundException | SQLException e) {
    41. e.printStackTrace();
    42. }
    43. return null ;
    44. }
    45. protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
    46. try {
    47. if (rs != null) {
    48. rs.close();
    49. }
    50. if(psmt!=null){
    51. psmt.close();
    52. }
    53. if(conn!=null && !conn.isClosed()){
    54. conn.close();
    55. }
    56. } catch (SQLException e) {
    57. e.printStackTrace();
    58. }
    59. }
    60. //给预处理命令对象设置参数
    61. private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
    62. if(params!=null && params.length>0){
    63. for (int i = 0; i < params.length; i++) {
    64. psmt.setObject(i+1,params[i]);
    65. }
    66. }
    67. }
    68. //执行更新,返回影响行数
    69. protected int executeUpdate(String sql , Object... params){
    70. boolean insertFlag = false ;
    71. insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
    72. try {
    73. conn = getConn();
    74. if(insertFlag){
    75. psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
    76. }else {
    77. psmt = conn.prepareStatement(sql);
    78. }
    79. setParams(psmt,params);
    80. int count = psmt.executeUpdate() ;
    81. rs = psmt.getGeneratedKeys();
    82. if(rs.next()){
    83. return ((Long)rs.getLong(1)).intValue();
    84. }
    85. return count ;
    86. } catch (SQLException e) {
    87. e.printStackTrace();
    88. }finally {
    89. close(rs,psmt,conn);
    90. }
    91. return 0;
    92. }
    93. //通过反射技术给obj对象的property属性赋propertyValue值
    94. private void setValue(Object obj , String property , Object propertyValue){
    95. Class clazz = obj.getClass();
    96. try {
    97. //获取property这个字符串对应的属性名 , 比如 "fid" 去找 obj对象中的 fid 属性
    98. Field field = clazz.getDeclaredField(property);
    99. if(field!=null){
    100. field.setAccessible(true);
    101. field.set(obj,propertyValue);
    102. }
    103. } catch (NoSuchFieldException | IllegalAccessException e) {
    104. e.printStackTrace();
    105. }
    106. }
    107. //执行复杂查询,返回例如统计结果
    108. protected Object[] executeComplexQuery(String sql , Object... params){
    109. try {
    110. conn = getConn() ;
    111. psmt = conn.prepareStatement(sql);
    112. setParams(psmt,params);
    113. rs = psmt.executeQuery();
    114. //通过rs可以获取结果集的元数据
    115. //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
    116. ResultSetMetaData rsmd = rs.getMetaData();
    117. //获取结果集的列数
    118. int columnCount = rsmd.getColumnCount();
    119. Object[] columnValueArr = new Object[columnCount];
    120. //6.解析rs
    121. if(rs.next()){
    122. for(int i = 0 ; i
    123. Object columnValue = rs.getObject(i+1); //33 苹果 5
    124. columnValueArr[i]=columnValue;
    125. }
    126. return columnValueArr ;
    127. }
    128. } catch (SQLException e) {
    129. e.printStackTrace();
    130. } finally {
    131. close(rs,psmt,conn);
    132. }
    133. return null ;
    134. }
    135. //执行查询,返回单个实体对象
    136. protected T load(String sql , Object... params){
    137. try {
    138. conn = getConn() ;
    139. psmt = conn.prepareStatement(sql);
    140. setParams(psmt,params);
    141. rs = psmt.executeQuery();
    142. //通过rs可以获取结果集的元数据
    143. //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
    144. ResultSetMetaData rsmd = rs.getMetaData();
    145. //获取结果集的列数
    146. int columnCount = rsmd.getColumnCount();
    147. //6.解析rs
    148. if(rs.next()){
    149. T entity = (T)entityClass.newInstance();
    150. for(int i = 0 ; i
    151. String columnName = rsmd.getColumnName(i+1); //fid fname price
    152. Object columnValue = rs.getObject(i+1); //33 苹果 5
    153. setValue(entity,columnName,columnValue);
    154. }
    155. return entity ;
    156. }
    157. } catch (SQLException e) {
    158. e.printStackTrace();
    159. } catch (IllegalAccessException e) {
    160. e.printStackTrace();
    161. } catch (InstantiationException e) {
    162. e.printStackTrace();
    163. } finally {
    164. close(rs,psmt,conn);
    165. }
    166. return null ;
    167. }
    168. //执行查询,返回List
    169. protected List executeQuery(String sql , Object... params){
    170. List list = new ArrayList<>();
    171. try {
    172. conn = getConn() ;
    173. psmt = conn.prepareStatement(sql);
    174. setParams(psmt,params);
    175. rs = psmt.executeQuery();
    176. //通过rs可以获取结果集的元数据
    177. //元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
    178. ResultSetMetaData rsmd = rs.getMetaData();
    179. //获取结果集的列数
    180. int columnCount = rsmd.getColumnCount();
    181. //6.解析rs
    182. while(rs.next()){
    183. T entity = (T)entityClass.newInstance();
    184. for(int i = 0 ; i
    185. String columnName = rsmd.getColumnName(i+1); //fid fname price
    186. Object columnValue = rs.getObject(i+1); //33 苹果 5
    187. setValue(entity,columnName,columnValue);
    188. }
    189. list.add(entity);
    190. }
    191. } catch (SQLException e) {
    192. e.printStackTrace();
    193. } catch (IllegalAccessException e) {
    194. e.printStackTrace();
    195. } catch (InstantiationException e) {
    196. e.printStackTrace();
    197. } finally {
    198. close(rs,psmt,conn);
    199. }
    200. return list ;
    201. }
    202. }

    FruitDAOImpl类

    1. package com.fruit.dao.impl;
    2. import com.fruit.dao.FruitDAO;
    3. import com.fruit.dao.base.BaseDAO;
    4. import com.fruit.pojo.Fruit;
    5. import java.util.List;
    6. public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
    7. @Override
    8. public List<Fruit> getFruitList() {
    9. return super.executeQuery("select * from t_fruit");
    10. }
    11. @Override
    12. public boolean addFruit(Fruit fruit) {
    13. String sql = "insert into t_fruit values(0,?,?,?,?)";
    14. int count = super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark()) ;
    15. //insert语句返回的是自增列的值,而不是影响行数
    16. //System.out.println(count);
    17. return count>0;
    18. }
    19. @Override
    20. public boolean updateFruit(Fruit fruit) {
    21. String sql = "update t_fruit set fcount = ? where fid = ? " ;
    22. return super.executeUpdate(sql,fruit.getFcount(),fruit.getFid())>0;
    23. }
    24. @Override
    25. public Fruit getFruitByFname(String fname) {
    26. return super.load("select * from t_fruit where fname like ? ",fname);
    27. }
    28. @Override
    29. public boolean delFruit(String fname) {
    30. String sql = "delete from t_fruit where fname like ? " ;
    31. return super.executeUpdate(sql,fname)>0;
    32. }
    33. }

    FruitDAO抽象类

    1. import com.fruit.pojo.Fruit;
    2. import java.util.List;
    3. public interface FruitDAO {
    4. //查询库存列表
    5. List getFruitList();
    6. //新增库存
    7. boolean addFruit(Fruit fruit);
    8. //修改库存
    9. boolean updateFruit(Fruit fruit);
    10. //根据名称查询特定库存
    11. Fruit getFruitByFname(String fname);
    12. //删除特定库存记录
    13. boolean delFruit(String fname);
    14. }

    Fruit类

    1. package com.fruit.pojo;
    2. public class Fruit {
    3. private Integer fid ;
    4. private String fname ;
    5. private Integer price ;
    6. private Integer fcount ;
    7. private String remark ;
    8. public Fruit(){}
    9. public Fruit(Integer fid, String fname, Integer price, Integer fcount, String remark) {
    10. this.fid = fid;
    11. this.fname = fname;
    12. this.price = price;
    13. this.fcount = fcount;
    14. this.remark = remark;
    15. }
    16. public Integer getFid() {
    17. return fid;
    18. }
    19. public void setFid(Integer fid) {
    20. this.fid = fid;
    21. }
    22. public String getFname() {
    23. return fname;
    24. }
    25. public void setFname(String fname) {
    26. this.fname = fname;
    27. }
    28. public Integer getPrice() {
    29. return price;
    30. }
    31. public void setPrice(Integer price) {
    32. this.price = price;
    33. }
    34. public Integer getFcount() {
    35. return fcount;
    36. }
    37. public void setFcount(Integer fcount) {
    38. this.fcount = fcount;
    39. }
    40. public String getRemark() {
    41. return remark;
    42. }
    43. public void setRemark(String remark) {
    44. this.remark = remark;
    45. }
    46. @Override
    47. public String toString() {
    48. return fid + "\t\t" + fname + "\t\t" + price +"\t\t" + fcount +"\t\t" + remark ;
    49. }
    50. }

    三、使用TomCat新建项目

    见前一文章。

    四、Servlet获取参数

    web文件结构

    hello.html文件

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>Titletitle>
    6. head>
    7. <body>
    8. <form action="add" method="post">
    9. 名称:<input type="text" name="fname"/><br/>
    10. 价格:<input type="text" name="price"/><br/>
    11. 库存:<input type="text" name="fcount"/><br/>
    12. 备注:<input type="text" name="remark"/><br/>
    13. <input type="submit" value="添加"/>
    14. form>
    15. body>
    16. html>

    web.xml文件

    此文件用于通过html中表单的action找到对应的类。

    此文件执行步骤:

            1、用户发请求,(action=add)
            2、项目中,web.xml中找到url-pattern = /add
            3、找servlet-name=com.fruit.servlets.AddServlet
            4、找和servlet-mapping中servlet-name一致的servlet
            5、找servlet-class
            6、用户发送的是post请求,tomcat会执行AddServlet中的doPost方法

    1. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    4. version="4.0">
    5. <servlet>
    6. <servlet-name>AddServletservlet-name>
    7. <servlet-class>com.servlets.AddServletservlet-class>
    8. servlet>
    9. <servlet-mapping>
    10. <servlet-name>AddServletservlet-name>
    11. <url-pattern>/addurl-pattern>
    12. servlet-mapping>
    13. web-app>

    AddServlet类

    此类分为两部分:接收客户端数据和向数据库发送数据。

    可能存在HttpServlet不存在问题,往下看。

    1. package com.servlets;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. import com.fruit.dao.FruitDAO;
    8. import com.fruit.dao.impl.FruitDAOImpl;
    9. import com.fruit.pojo.Fruit;
    10. public class AddServlet extends HttpServlet {
    11. @Override
    12. /**接收客户端发送数据*/
    13. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    14. request.setCharacterEncoding("utf-8");//解决输入中文乱码问题
    15. String fname = request.getParameter("fname");
    16. String priceStr = request.getParameter("price");
    17. Integer price = Integer.parseInt(priceStr);
    18. String fcountStr = request.getParameter("fcount");
    19. Integer fcount = Integer.parseInt(fcountStr);
    20. String remark = request.getParameter("remark");
    21. /**向数据库发送数据*/
    22. FruitDAO fruitDAO = new FruitDAOImpl();
    23. boolean flag = fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
    24. System.out.println(flag ? "添加成功":"添加失败");
    25. }
    26. }

    HttpServlet不存在解决:

    选择库中的Tomcat并确定。

    此时,外部库中有了servlet-api

     其他问题:

    打开项目结构,查看是否还有问题,如有直接修复

     五、测试

    输入信息,点击添加,数据库中出现数据信息,表示成功。


     

     

     

  • 相关阅读:
    SpringBoot和SpringCloud的区别,使用微服务的好处和缺点
    发明专利快速预审多久出结果?
    1.13.C++项目:仿muduo库实现并发服务器之TcpServer模块的设计
    中缀表达式转后缀表达式详细思路及代码实现
    自定义类型:结构体(内存对齐),枚举,联合
    解决chrome extension popup最大宽高限制(800x600)
    JavaOOP-类、对象、方法、变量作用域及JavaDoc注释
    day04_java基础
    【SpringCloud-学习笔记】Nacos配置管理
    什么是副业思维,副业应该怎么做,用创业思维分析副业的可行性
  • 原文地址:https://blog.csdn.net/Tir_zhang/article/details/126101192