title: "JDBC+Servlet"
date: 2019-08-19T15:06:02+08:00
本章内容为:《JDBC+Servlet完成商品管理系统》
作者:nuoccc
这篇文章是基于JDBC+Servlet来完成一个商品管理系统,是基于对上一篇文章《Servlet基础2》的加强版。
首先先对上一篇文章的结尾抛出的问题进行处理,首先是耦合度的问题,为了降低耦合度,我们现在一般是用三层来完成Java代码,分别为Dao层,Service层和Bean层。
Dao层叫数据访问层,全称为data access object,属于一种比较底层,比较基础的操作,具体到对于某个表、某个实体的增删改查,所以我们一般进行的对数据库的操作就封装到Dao层。
Service叫服务层,被称为服务,肯定是相比之下比较高层次的一层结构,相当于将几种操作封装起来。
Bean层叫做实体层,主要是某个实体类的属性定义。
然后解决了耦合度我们,我们再来解决一下Servlet太多的问题,我们之前是每一个页面一个Servlet,现在我们改成每一个对象一个Servlet,比如完成用户的登录,注册,增加,删除,我们就只创一个UserServlet,在一个Servlet中完成各自操作。接下来,完成一个商品管理系统的编写。
1.用户注册页面
首先还是我们用户注册页面,只有注册登录之后才能访问我们的管理系统。
然后还是先创建一个项目,然后放入我们的驱动,工具类之后,再创建一个注册的JSP文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
注册页面
之后我们再创建对应的数据库
Create table testJAS_user(
id int(4) primary key auto_increment,
username varchar(20) not null,
password varchar(20) not null,
idCard varchar(18) not null,
phonenumber varchar(13) not null,
address varchar(30) not null,
email varchar(20) not null
)engine=innodb default charset=utf8;
创建好数据库之后,我们来创建三层,首先创建Bean层
public class UserBean {
private long id;
private String username;
private String password;
private String idcard;
private String phonenumber;
private String address;
private String email;
public UserBean() {
}
public UserBean(String username, String password) {
this.username = username;
this.password = password;
}
public UserBean(String username, String password, String idcard, String phonenumber, String address, String email) {
this.username = username;
this.password = password;
this.idcard = idcard;
this.phonenumber = phonenumber;
this.address = address;
this.email = email;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIdcard() {
return idcard;
}
public void setIdcard(String idcard) {
this.idcard = idcard;
}
public String getPhonenumber() {
return phonenumber;
}
public void setPhonenumber(String phonenumber) {
this.phonenumber = phonenumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", idcard='" + idcard + '\'' +
", phonenumber='" + phonenumber + '\'' +
", address='" + address + '\'' +
", email='" + email + '\'' +
'}';
}
}
然后再创建Dao层和Service层并创建对应的文件
最后我们再创建一个Servlet包,来创建我们的Servlet
然后我们不是说要把所以操作都放在一个Servlet里面来做,但如何实现呢?
我们是通过在jsp文件隐藏一个input框,根据它的值来判断进行什么操作
代码如下:
前面的jsp代码也加入了,可以仔细找找,有了这个我们就可以进行判断不同的操作,然后根据操作来实现不同的代码。
@WebServlet("/UserServlet.do")
public class UserServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
req.setCharacterEncoding("utf-8");
//设置字符集
UserServiceImp usi = new UserServiceImp();
//创建Service实现类对象
String action=req.getParameter("action");
//获取隐藏表单的action属性值
if("Register".equals(action)){
//如果这个操作是注册操作
String username = req.getParameter("username");
String password = req.getParameter("password");
String idCard = req.getParameter("idCard");
String phonenumber = req.getParameter("phonenumber");
String address = req.getParameter("address");
String email = req.getParameter("email");
//获取各个属性
UserBean user = new UserBean(username,password,idCard,phonenumber,address,email);
//封装到Bean层的对象内
int count = usi.userRegister(user);
/*然后调用Service实现类的注册方法,现在我们还没有就去创建一个这个方法。这个方法返回一个count,为1代表插入成功,为0代表插入失败*/
if(count>0){
resp.getWriter().write("");
//注册成功的话,提示注册成功,并跳往登录页面
}else{
resp.getWriter().write("");
//注册失败的话,提示注册失败,并重新注册
}
}
}
}
写完Servlet我们发现还需要用Service的方法,于是我们去Service创建以下方法:
public class UserServiceImp implements UserService {
@Override
public int userRegister(UserBean user) {
UserDaoImp udi = new UserDaoImp();
udi.userRegister(user);
//调用Dao的方法,来实现数据库的操作
}
}
同样的,我们要进行操作,就需要用Dao层来实现操作,所以我们还需要调用Dao层的方法,同样现在没有需要我们创建这样的方法,代码如下:
public class UserDaoImp extends BaseDao implements UserDao{
@Override
public int userRegister(UserBean user) {
String sql = "insert into testjas_user value(null,?,?,?,?,?,?)";
//数据库插入语句
Object[] parms ={
user.getUsername(),
user.getPassword(),
user.getIdcard(),
user.getPhonenumber(),
user.getAddress(),
user.getEmail()
};
//获取具体的值
int count = myExecuteUpdate(sql,parms);
//执行插入语句
return count;
}
}
这样我们一个基于JDBC+Servlet的注册页面就完成了,我们之后来进行登录页面的完成。
2.用户登录页面
首先先创建一个Login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
登录页面
然后就去我们的UserServlet完成逻辑代码。
但是我们看之前的代码,如果我们再写一个if判断会显得代码很多,于是为了代码的整洁性,我们把代码抽取出来。
当我们需要看那段代码时就可以收起来,这样代码就会看着简洁,也方便我们维护代码。
然后我们继续我们Login的条件判断
if("Login".equals(action)){
//判断如果是登录操作
String username = req.getParameter("username");
String password = req.getParameter("password");
//获取表单输入框内的数据
UserBean user = new UserBean(username,password);
//封装成一个user对象
ResultSet rs = usi.userLogin(user);
//返回一个结果集,如果结果集有值代表数据库有这么一行数据
try {
if(rs.next()){
resp.getWriter().write("");
//登录成功跳转商品首页,为什么跳转地址要写这个接下来分析
}else {
resp.getWriter().write("");
//失败跳转登录页面
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
然后去Service层userLogin方法
public class UserServiceImp implements UserService {
UserDaoImp udi = new UserDaoImp();
@Override
public int userRegister(UserBean user) {
return udi.userRegister(user);
}
@Override
public ResultSet userLogin(UserBean user) {
return udi.userLogin(user);
}
//Service层的登录方法,去调用Dao层的登录方法
}
然后去Dao层实现数据库的操作
public ResultSet userLogin(UserBean user) {
String sql = "select * from testjas_user where username=? and password=?";
//数据库查询语言
Object[] parms = {
user.getUsername(),
user.getPassword()
};
//获得用户名和密码
ResultSet rs = myExecuteQuery(sql,parms);
//执行数据库查询操作并返回一个结果集
return rs;
}
这样就完成我们的登录页面也就完成了,接下来就是我们的商品首页
3.商品添加功能
但在我们商品首页需要去展示所有的商品,现在还没有,所有我们需要先创建一个商品添加页面
由于商品是一个新的对象,所有我们需要先创建一个新的表已经Servelt,首先先创一个Product表
CREATE TABLE `testjas_product` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`productname` varchar(20) NOT NULL,
`inprice` double NOT NULL,
`outprice` double NOT NULL,
`uptime` date NOT NULL,
`number` int(10) NOT NULL,
`description` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
然后创建对应的ProductServlet,dao,bean,service,然后我们开始添加ProductAdd.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
My JSP 'add.jsp' starting page
同样的别忘记加隐藏标签来区分操作
然后我们现在来ProductServlet进行判断以及后续操作
@WebServlet("/ProductServlet.do")
public class ProductServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charser=utf-8");
//设置字符集
ProductServiceImp psi = new ProductServiceImp();
//获得Service层对象
String action = req.getParameter("action");
//获取操作
if("ProductAdd".equals(action)){
//如果是添加商品功能
String name = req.getParameter("name");
String inprice = req.getParameter("inprice");
String outprice = req.getParameter("outprice");
String uptime = req.getParameter("uptime");
String number = req.getParameter("number");
String description = req.getParameter("description");
//获取属性
ProductBean product = new ProductBean(name,Double.parseDouble(inprice),Double.parseDouble(outprice), Date.valueOf(uptime),Integer.parseInt(number),description);
//封装成Product对象
int count = psi.productAdd(product);
//调用Service层的添加商品方法,并返回一个count为1代表成功,为0失败
if(count>0){
resp.getWriter().write("");
}else {
resp.getWriter().write("");
}
}
}
}
然后我们去Service层创建productAdd方法
public class ProductServiceImp implements ProductService {
ProductDaoImp pdi= new ProductDaoImp();
@Override
public int productAdd(ProductBean product) {
return pdi.productAdd(product);
//调用Dao层对象完成数据库的操作
}
}
然后我们再去Dao层创建productAdd方法来实现数据库的操作
public class ProductDaoImp extends BaseDao implements ProductDao {
@Override
public int productAdd(ProductBean product) {
String sql = "insert into testjas_product value(null,?,?,?,?,?,?)";
//数据库插入语言
String name = product.getName();
Double inprice = product.getInprice();
Double outprice = product.getOutprice();
Date uptime = product.getUptime();
long number = product.getNumber();
String description = product.getDescription();
//获取属性
Object[] parms = {name,inprice,outprice,uptime,number,description};
int count = myExecuteUpdate(sql,parms) ;
//数据库执行插入语句
return count;
}
}
这样我们一个商品新增功能就完成了,然后现在我们数据库有了商品内容我们就可以去实现我们的首页展示了
4.商品首页展示
首先我们来创建一个ProductRead.jsp也就是商品首页的jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
商品首页
这个jsp跟之前的不同,这个是要首先去获得动态数据,不再像我们之前的页面是一个死页面,所以我们之前写登录成功之后的页面跳转页没有直接写ProductRead.jsp,然后我们再来详细分析一下这个jsp为什么这么写。这里有一个小知识点就是例如ProductSevrlet.do?action=ProductRead,这里?后面的代表的是属性
首先还是先来完成我们的Sevrlet,因为我们先要去便历我们的商品
if("ProductRead".equals(action)){
//如果是查询所有商品
ResultSet rs = psi.productRead();
//调用Service层的查询所有商品,如果查到了就返回一个结果集
try {
List ls = new ArrayList();
//创建一个集合
while(rs.next()){
//便历这个结果集
int id = rs.getInt(1);
String name = rs.getString(2);
double inprice = rs.getDouble(3);
double outprice = rs.getDouble(4);
Date uptime = rs.getDate(5);
Long number = rs.getLong(6);
String description = rs.getString(7);
ProductBean p = new ProductBean(id,name,inprice,outprice,uptime,number,description);
ls.add(p);
//把结果集的所有数据封装成商品对象,并添加到集合中
}
req.setAttribute("productRead",ls);
//请求设置一个名为productRead的属性,值为集合
req.getRequestDispatcher("ProductRead.jsp").forward(req,resp);
//最后再跳转到有数据的页面
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
然后我们再去Service层去实现方法
public ResultSet productRead() {
return pdi.productRead();
}
然后去Dao层完成具体的实现
@Override
public ResultSet productRead() {
String sql = "select * from testjas_product";
ResultSet rs =myExecuteQuery(sql,null);
return rs;
}
现在我们得到了数据,然后我们就回到一开始的为什么要那么设计jsp
因为我们只是Sevrlet获得到了数据,但要怎么让这个数据传到jsp呢?这时候就是 req.setAttribute("productRead",ls);这段代码起的作用,请求对象设置了一个属性并存了一个值,所以在我们的jsp页面中响应对象就能去获取这个值,也就是下面这段代码
<%
//从转发过来的request中把值取出来,获取出来默认是Object 需要转换类型
List list= (List)request.getAttribute("pros");
if(list!=null){
for(ProductBean p:list){
%>
<%
}
}
%>
我们再来分析一下这段代码,首先是这样的
<%
//从转发过来的request中把值取出来,获取出来默认是Object 需要转换类型
List list= (List)request.getAttribute("pros");
if(list!=null){
for(ProductBean p:list){
}
}
%>
首先我们响应对象拿到了这个属性的值,同样的需要一个一个集合来接受值,然后我们便历这个集合,便历这个集合干嘛呢?我每便历一次创建一条内容。所以我们把这段代码拆分成了两份,然后再中间放上我们的内容,这样一个动态的jsp页面就生成了。有了主页然后我们就要进行主页上的修改操作
5.商品修改
首先我们需要思考我们怎么来确定,我们选择的到底是哪一个商品,不知道前面的商品首页jsp页面有一段代码注意了没有
修改|
这段代码,我给修改加了一个id,这样我每一个修改其实都是独立的,那我为什么在action后面加的是gotoUpdate而不是ProductUpdate.jsp页面呢?这是我们知道我们平常点修改,是不是修改页面要有我们需要修改的数据,如果直接是Update的页面,那是一个死页面,只有Input框,所以我们这里需要一个过渡操作,先把首页商品的内容传到ProductUpdate页面里面,所以我们需要通过id再去访问一次数据库拿到所有数据再放到Update页面里面,首先还是创建productUpdate.jsp,才知道我们到底需要什么内容。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
My JSP 'add.jsp' starting page
<%
ProductBean p = (ProductBean) request.getAttribute("gotoUpdate");
%>
然后我们需要先去获得数据,同意的先在Sevrlet进行操作判断
if("gotoUpdate".equals(action)){
//如果是跳转更新页面的操作
ProductBean p = null;
//创建一个空对象
String id = req.getParameter("id");
//获取商品的id
ResultSet rs = psi.gotoUpdate(id);
//去获取需要更新的数据,并返回一个结果集
try {
if(rs.next()){
//如果通过id找到了这一行数据
String name = rs.getString(2);
double inprice = rs.getDouble(3);
double outprice = rs.getDouble(4);
Date uptime = rs.getDate(5);
Long number = rs.getLong(6);
String description = rs.getString(7);
//获得这一行数据的各个值
p = new ProductBean(Integer.parseInt(id),name,inprice,outprice,uptime,number,description);
//封装成商品对象
}
req.setAttribute("gotoUpdate",p);
//然后请求对象把对象储存在gotoUpdate里面
} catch (SQLException e) {
e.printStackTrace();
} finally {
}
}
然后我们去Service层创建gotoUpdate方法
@Override
public ResultSet gotoUpdate(String id) {
return pdi.gotoUpdate(id);
}
然后去Dao层实现数据库的操作
@Override
public ResultSet gotoUpdate(String id) {
String sql = "select * from testjas_product where id =?";
Object[] parms={id};
ResultSet rs = myExecuteQuery(sql,parms);
return rs;
}
这样我们就得到了数据,然后我们再显示在数据框,前面jsp代码已经实现了,然后我们修改完数据之后,再进行数据的更新提交更新传递给数据库。但是更新我们要保持id的一致,所以别忘了藏一个id标签
然后我们到Servlet进行真正的数据库更新操作
if("ProductUpdate".equals(action)){
//如果是数据库更新操作
String id = req.getParameter("id");
String name = req.getParameter("name");
String inprice = req.getParameter("inprice");
String outprice = req.getParameter("outprice");
String uptime = req.getParameter("uptime");
String number = req.getParameter("number");
String description = req.getParameter("description");
//获取各个属性
ProductBean product = new ProductBean(Integer.parseInt(id),name,Double.parseDouble(inprice),Double.parseDouble(outprice),Date.valueOf(uptime),Integer.parseInt(number),description);
//封装成商品对象
int count = psi.productUpdate(product);
//调用Sevrice层方法,更新商品成功返回1失败返回0
if(count>0){
resp.getWriter().write("");
}else{
resp.getWriter().write("");
}
//注意重定向时,一定要定向带数据的页面,不要跳转死页面
}
然后我们去Service层实现数据库更新方法
@Override
public int productUpdate(ProductBean product) {
return pdi.productUpdate(product);
}
然后Dao层去实现数据库操作
@Override
public int productUpdate(ProductBean product) {
String sql = "Update testjas_product set name=?,inprice=?,outprice=?,uptime=?,name=?,description=? where id=?";
Object[] parms={
product.getName(),
product.getInprice(),
product.getOutprice(),
product.getUptime(),
product.getNumber(),
product.getDescription(),
product.getId()
};
int count = myExecuteUpdate(sql,parms);
return count;
}
这样我们的更新就完成了,最后就是我们的删除操作
6. 商品删除
同样的我们删除商品的时候,需要获取这个商品的id,但是与更新不同的是,删除的时候其实会有个弹窗怕用户误操作不小心删了,所以在首页的删除操作我是这么实现的,前面jsp也写了的
删除
然后再javascript代码中进行提醒
如果用户确实要进行删除操作,这时候我们就在Servlet来进行操作
if("ProductDelete".equals(action)){
String id = req.getParameter("id");
int count = psi.productDelete(id);
try {
if (count>0) {
resp.getWriter().write("");
}else{
resp.getWriter().write("");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
然后再Servicec层创建productDelete删除方法
@Override
public int productDelete(String id) {
return pdi.productDelete(id);
}
然后我们再到Dao层完成数据库的操作
@Override
public int productDelete(String id) {
String sql = "delete from testjas_product where id=?";
Object[] parms = {id};
int count = myExecuteUpdate(sql,parms);
return count;
}
这样我们的删除操作也完成了,整个商品系统最基础的登录注册CRUD也就完成了。