Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
web获取参数到数据库的原理:
Web(用户)首先请求http页面,web服务器对其响应显示页面;
用户点击表单提交按钮,调用(request)服务器端的add(表单中定义的action),add调用java类;
java类中包括获取用户发送的数据操作、调用DAO中的方法添加到数据库、控制台打印。
下面使用idea2022企业版+mysql8。
代码实现
下面以以下表格为题示例。
一、创建数据库表
CREATE TABLE 't_fruit' (
'fid' INT(11) NOT NULL AUTO_INCREMENT,
'fname' VARCHAR(20) NOT NULL,
'price' INT(11) DEFAULT NULL,
'fcount' INT(11) DEFAULT NULL,
'remark' VARCHAR(50) DEFAULT NULL,
PRIMARY KEY ('fid')
) ENGINE=INNODB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;
二、实现操作数据库
1、加载驱动
创建lib文件,将驱动文件复制进去并将文件添加为库。
2、DAO
使用DAO对数据库操作。
文件结构:
BaseDAO类
其中,URL 3306/ 后面为数据库名字;
USER 为用户名;
PWD为密码;
注意修改!
package com.fruit.dao.base;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseDAO<T> {
public final String DRIVER = "com.mysql.jdbc.Driver" ;
public final String URL = "jdbc:mysql://localhost:3306/javaweb?useUnicode=true&characterEncoding=utf-8&useSSL=false";
public final String USER = "root";
public final String PWD = "ad" ;
protected Connection conn ;
protected PreparedStatement psmt ;
protected ResultSet rs ;
//T的Class对象
private Class entityClass ;
public BaseDAO(){
//getClass() 获取Class对象,当前我们执行的是new FruitDAOImpl() , 创建的是FruitDAOImpl的实例
//那么子类构造方法内部首先会调用父类(BaseDAO)的无参构造方法
//因此此处的getClass()会被执行,但是getClass获取的是FruitDAOImpl的Class
//所以getGenericSuperclass()获取到的是BaseDAO的Class
Type genericType = getClass().getGenericSuperclass();
//ParameterizedType 参数化类型
Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
//获取到的<T>中的T的真实的类型
Type actualType = actualTypeArguments[0];
try {
entityClass = Class.forName(actualType.getTypeName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
protected Connection getConn(){
try {
//1.加载驱动
Class.forName(DRIVER);
//2.通过驱动管理器获取连接对象
return DriverManager.getConnection(URL, USER, PWD);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
return null ;
}
protected void close(ResultSet rs , PreparedStatement psmt , Connection conn){
try {
if (rs != null) {
rs.close();
}
if(psmt!=null){
psmt.close();
}
if(conn!=null && !conn.isClosed()){
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//给预处理命令对象设置参数
private void setParams(PreparedStatement psmt , Object... params) throws SQLException {
if(params!=null && params.length>0){
for (int i = 0; i < params.length; i++) {
psmt.setObject(i+1,params[i]);
}
}
}
//执行更新,返回影响行数
protected int executeUpdate(String sql , Object... params){
boolean insertFlag = false ;
insertFlag = sql.trim().toUpperCase().startsWith("INSERT");
try {
conn = getConn();
if(insertFlag){
psmt = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
}else {
psmt = conn.prepareStatement(sql);
}
setParams(psmt,params);
int count = psmt.executeUpdate() ;
rs = psmt.getGeneratedKeys();
if(rs.next()){
return ((Long)rs.getLong(1)).intValue();
}
return count ;
} catch (SQLException e) {
e.printStackTrace();
}finally {
close(rs,psmt,conn);
}
return 0;
}
//通过反射技术给obj对象的property属性赋propertyValue值
private void setValue(Object obj , String property , Object propertyValue){
Class clazz = obj.getClass();
try {
//获取property这个字符串对应的属性名 , 比如 "fid" 去找 obj对象中的 fid 属性
Field field = clazz.getDeclaredField(property);
if(field!=null){
field.setAccessible(true);
field.set(obj,propertyValue);
}
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
//执行复杂查询,返回例如统计结果
protected Object[] executeComplexQuery(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
Object[] columnValueArr = new Object[columnCount];
//6.解析rs
if(rs.next()){
for(int i = 0 ; i<columnCount;i++){
Object columnValue = rs.getObject(i+1); //33 苹果 5
columnValueArr[i]=columnValue;
}
return columnValueArr ;
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
//执行查询,返回单个实体对象
protected T load(String sql , Object... params){
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
if(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
setValue(entity,columnName,columnValue);
}
return entity ;
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return null ;
}
//执行查询,返回List
protected List<T> executeQuery(String sql , Object... params){
List<T> list = new ArrayList<>();
try {
conn = getConn() ;
psmt = conn.prepareStatement(sql);
setParams(psmt,params);
rs = psmt.executeQuery();
//通过rs可以获取结果集的元数据
//元数据:描述结果集数据的数据 , 简单讲,就是这个结果集有哪些列,什么类型等等
ResultSetMetaData rsmd = rs.getMetaData();
//获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.解析rs
while(rs.next()){
T entity = (T)entityClass.newInstance();
for(int i = 0 ; i<columnCount;i++){
String columnName = rsmd.getColumnName(i+1); //fid fname price
Object columnValue = rs.getObject(i+1); //33 苹果 5
setValue(entity,columnName,columnValue);
}
list.add(entity);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} finally {
close(rs,psmt,conn);
}
return list ;
}
}
FruitDAOImpl类
package com.fruit.dao.impl;
import com.fruit.dao.FruitDAO;
import com.fruit.dao.base.BaseDAO;
import com.fruit.pojo.Fruit;
import java.util.List;
public class FruitDAOImpl extends BaseDAO<Fruit> implements FruitDAO {
@Override
public List<Fruit> getFruitList() {
return super.executeQuery("select * from t_fruit");
}
@Override
public boolean addFruit(Fruit fruit) {
String sql = "insert into t_fruit values(0,?,?,?,?)";
int count = super.executeUpdate(sql,fruit.getFname(),fruit.getPrice(),fruit.getFcount(),fruit.getRemark()) ;
//insert语句返回的是自增列的值,而不是影响行数
//System.out.println(count);
return count>0;
}
@Override
public boolean updateFruit(Fruit fruit) {
String sql = "update t_fruit set fcount = ? where fid = ? " ;
return super.executeUpdate(sql,fruit.getFcount(),fruit.getFid())>0;
}
@Override
public Fruit getFruitByFname(String fname) {
return super.load("select * from t_fruit where fname like ? ",fname);
}
@Override
public boolean delFruit(String fname) {
String sql = "delete from t_fruit where fname like ? " ;
return super.executeUpdate(sql,fname)>0;
}
}
FruitDAO抽象类
import com.fruit.pojo.Fruit;
import java.util.List;
public interface FruitDAO {
//查询库存列表
List<Fruit> getFruitList();
//新增库存
boolean addFruit(Fruit fruit);
//修改库存
boolean updateFruit(Fruit fruit);
//根据名称查询特定库存
Fruit getFruitByFname(String fname);
//删除特定库存记录
boolean delFruit(String fname);
}
Fruit类
package com.fruit.pojo;
public class Fruit {
private Integer fid ;
private String fname ;
private Integer price ;
private Integer fcount ;
private String remark ;
public Fruit(){}
public Fruit(Integer fid, String fname, Integer price, Integer fcount, String remark) {
this.fid = fid;
this.fname = fname;
this.price = price;
this.fcount = fcount;
this.remark = remark;
}
public Integer getFid() {
return fid;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public String getFname() {
return fname;
}
public void setFname(String fname) {
this.fname = fname;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public Integer getFcount() {
return fcount;
}
public void setFcount(Integer fcount) {
this.fcount = fcount;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
@Override
public String toString() {
return fid + "\t\t" + fname + "\t\t" + price +"\t\t" + fcount +"\t\t" + remark ;
}
}
三、使用TomCat新建项目
见前一文章。
四、Servlet获取参数
web文件结构
hello.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="add" method="post">
名称:<input type="text" name="fname"/><br/>
价格:<input type="text" name="price"/><br/>
库存:<input type="text" name="fcount"/><br/>
备注:<input type="text" name="remark"/><br/>
<input type="submit" value="添加"/>
</form>
</body>
</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方法
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>AddServlet</servlet-name>
<servlet-class>com.servlets.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
</web-app>
AddServlet类
此类分为两部分:接收客户端数据和向数据库发送数据。
可能存在HttpServlet不存在问题,往下看。
package com.servlets;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import com.fruit.dao.FruitDAO;
import com.fruit.dao.impl.FruitDAOImpl;
import com.fruit.pojo.Fruit;
public class AddServlet extends HttpServlet {
@Override
/**接收客户端发送数据*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");//解决输入中文乱码问题
String fname = request.getParameter("fname");
String priceStr = request.getParameter("price");
Integer price = Integer.parseInt(priceStr);
String fcountStr = request.getParameter("fcount");
Integer fcount = Integer.parseInt(fcountStr);
String remark = request.getParameter("remark");
/**向数据库发送数据*/
FruitDAO fruitDAO = new FruitDAOImpl();
boolean flag = fruitDAO.addFruit(new Fruit(0,fname,price,fcount,remark));
System.out.println(flag ? "添加成功":"添加失败");
}
}
HttpServlet不存在解决:
选择库中的Tomcat并确定。
此时,外部库中有了servlet-api
其他问题:
打开项目结构,查看是否还有问题,如有直接修复
五、测试
输入信息,点击添加,数据库中出现数据信息,表示成功。