【开发日志】第三天 --- 购物车购买清空功能
引言:
1、博主目标是成为一名Java开发工程师,所以自学JavaEE,这是博主第一个实战项目,希望将开发过程记录下来,如果有错误,请各位看官评论留言,我一定虚心求教,认真改正。
2、另外此次实战只是我的第一阶段实战,并未用到mybatis和spring框架实现,仅仅用了jsp,servlet,html,css,mvc框架,JDBC技术,比较老套以及繁琐,意在于锻炼基础,以便以后对框架理解更为深入,增加核心竞争力。
3、此篇博客是第一个功能块的实现,前期准备以及项目描述见:项目描述
4、目前代码不适用于重名的情况,对于不重名的情况没问题
基本思路:
前端
1、需要获得购物车信息,将购物车信息打印出来,要考虑购物车为空。
2、需要设计一个form表单,内置表格,将提交的要购买的商品信息以及商品数量传递到后台
3、设计一个判断登陆的模块,已经登陆的直接打印表单,没登陆的先登录或者注册,再显示购物车。
4、支持一键清空购物车(将该用户记录全部删除)
后端
1、servlet:要接收到前端发来的多选框,以及用户姓名,以及选中的商品的数量,发向service,再得到service的处理结果代码,根据不同的代码封装不同的情况再发往前端,在由前端显示结果。
2、service:这是这个后端的核心,所有逻辑算法错误处理都应该在这里!(博主因为经验不足,导致service书写的不好,好多逻辑处理放进了Dao层,我会在代码中进行标识),他是核心服务层。他得到service的三大数据,首先进行错误判断,将可能的三种错误经由error层处理返回错误代码。之后处理正确情况,先让Dao层进入DB查询相应选中商品价格,回到service 进行价格计算,然后让Dao层去把选中的商品置为null,同时删除五个商品栏全空的行,最后命令Dao将记录插入record表,再返回记录Id。
3、Dao:该层就是拿service处理好的精纯数据,来和数据库交互。功能一:进入DB查询相应选中商品价格。功能二:把选中的商品置为null,同时删除五个商品栏全为null的行。功能三:将消费记录插入record表。功能四:查询最新插入的记录Id,并返回。功能五:拿到用户名子查询用户Id。(本系统目前不支持重名)。
代码实现:
1、jsp前端
注:
1、购物车可以为空,必须单独判断
2、用户可能重复选择,必须过滤,并且过滤掉null的商品
3、注意text的表单控件,名字一定要不同,并且要用商品ID去拼名字,因为多选框传到后端的是商品ID,所以这样便于后端去拼出text传过来的名字。
<%@page import="com.webhomework.dao.showGoodsDao"%>
<%@page import="com.webhomework.javabeans.user"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.ArrayList"%>
<%@page import="com.webhomework.jdbc.JDBCTools"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String isLogIn = (String)session.getAttribute("name");//模块1,判定是否登录,用session
%>
<%
if(isLogIn != null){
%>
<%
//将所有goods打印出来,做成form表单,可以选择进入购物车
JDBCTools jdbct = new JDBCTools();
ArrayList<Map<String,String>> resultMapOne = new ArrayList<Map<String,String>>();
ArrayList<Map<String,String>> resultMapTwo = new ArrayList<Map<String,String>>();
ArrayList<String> commodityNumber = new ArrayList<String>();
user u = new user();
u.setName((String)session.getAttribute("name"));
showGoodsDao sgd = new showGoodsDao();
String id = sgd.findIdInDB(u);//利用Dao层功能五获得用户ID
String sql = "select goods_one,goods_two,goods_three,goods_four,goods_five,is_valid from user u ,goods_car gc where u.id=gc.user_id and u.id="+ id +" and is_valid=false;";
resultMapOne = jdbct.find(sql);//将查询到的该用户添加到购物车里的东西取出来
int numOne = resultMapOne.size();
%>
<%
if(numOne == 0){//判断购物车是否为空
%>
<div><b>购物车为空</b></div>
<div><a href="showGoods.jsp">点击添加商品</a></div>
<%
}
%>
<%
if(numOne > 0){
%>
<%for(int i = 0 ;i < resultMapOne.size() ;i++){//以下操作为过滤掉重复选择的商品以及为null商品,前者就是利用一个辅助List
//每进来一个就要与前面比较一下看有无重复,后者就是遍历的时候看一直与否即可
ArrayList<String> temp = new ArrayList<String>();
temp.add(resultMapOne.get(i).get("goods_one"));
temp.add(resultMapOne.get(i).get("goods_two"));
temp.add(resultMapOne.get(i).get("goods_three"));
temp.add(resultMapOne.get(i).get("goods_four"));
temp.add(resultMapOne.get(i).get("goods_five"));
for(int k = 0 ;k < 5 ;k++ ){
int j = 0;
int num = commodityNumber.size();
if(temp.get(k).equals("null")){
continue;
}
for(;j < num ;j++){
if(!temp.get(k).equals(commodityNumber.get(j))){
continue;
}
else{
break;
}
}
if(j == num){
commodityNumber.add(temp.get(k));
}
else{
continue;
}
}
}
String sqlAno = "select * from goods where";
int j = 0;
for(;j < commodityNumber.size() - 1 ;j++) {
String ano = " id="+ commodityNumber.get(j) +" or";
sqlAno += ano;
}
String ano = " id="+ commodityNumber.get(j) +";";
sqlAno += ano;
resultMapTwo = jdbct.find(sqlAno);//将查到的商品信息存起来一会打印到表格里面
int num = resultMapTwo.size();
%>
<form action="goodsCarServlet" method="post">//注意form里面不仅可以放表单控件,啥都可以放进去包括表格,所以可以采用表格中嵌入表单控件的方法
<table border="1">
<tr>
<th width="20"></th>
<th>商品名称</th>
<th>商品类型</th>
<th>商品数量</th>
<th>商品价格</th>
<td width="200">请输入您要的数量</td>
</tr>
<%
for(int i = 0 ;i < num ;i++){
%>
<tr>
<td width="20"><input type="checkbox" name="checkbox" class="check-product" value="<%=resultMapTwo.get(i).get("id") %>" /></td>
<td width="150" align="left"><%=resultMapTwo.get(i).get("name") %></td>
<td width="100" align="left"><%=resultMapTwo.get(i).get("type") %></td>
<td width="100" align="left"><%=resultMapTwo.get(i).get("num") %></td>
<td width="100" align="left"><%=resultMapTwo.get(i).get("price") %></td>
<%String Name = "num"+ resultMapTwo.get(i).get("id"); %>//拼名字,保证每个text名字不同,并且用商品ID便于后端接收
<td width="200">请输入您要的数量 <input type="text" name="<%=Name %>" id="" /></td>
</tr>
<%
}
%>
</table>
<input type="submit" value="点击结算购物车" />
</form>
<form action="deleteGoodsCarServlet" method="post">//一键清空购物车功能
<input type="submit" value="一键清空购物车" />
</form>
<%
}
%>
<%
}
%>
<%
if(isLogIn == null){//未登录处理
%>
<div>
<b>您好,您未登录,请先登录再观看您的购物车</b>
</div>
<div>
<a href="login.jsp">点击登录</a>
</div>
<%
}
%>
</body>
</html>
2、servlet
由前端走进后端,表单先被服务器拦截,根据xml的配置以及点击不同的按钮被分别发送到goodsCarServlet中,和deleteGoodsCarServlet中
1、goodsCarServlet
注:
1、服务层才是处理所有逻辑,书写算法,封装结果的地方,所以最好将结果的封装放到service层,博主这里犯错误了,在代码中标号1的位置,记住servlet就是干截数据,发送数据到service,最后在将结果转发的活。
package com.webhomework.control;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.webhomework.service.goodsCarService;//service层方法
import com.webhomework.service.showGoodsService;
public class goodsCarServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");//设置编码结构,防止中文乱码
Map<Integer,String> resultMap = new HashMap<Integer,String>();
ArrayList<String> numberList = new ArrayList<String>();
String[] result = request.getParameterValues("checkbox");//获取多选框数据
String name = (String)request.getSession().getAttribute("name");
int num = result.length;
for(int i = 0 ;i < num ;i++) {//这里就看出当时拼接Name的优势了,我直接根据选中的商品Id拼接,第一方便接收拼接名字,第二可以过滤掉无效提交
String Name = "num";
Name += result[i];
numberList.add(request.getParameter(Name).trim());
}
goodsCarService gcs = new goodsCarService();//将数据传送到服务层
int station = gcs.buyGoodsInCarService(result, name, numberList);
//获得服务层服务结果代码,正整数代表正确,且表示插入记录表中的Id号
switch(station) {//1、封装位置最好在service里面
//封装服务情况
case 0 :
resultMap.put(0, "对不起,购买失败,数据库异常");
break;
case -1 :
resultMap.put(-1, "对不起,购买失败,存在没填写的数");
break;
case -2 :
resultMap.put(-2, "对不起,购买失败,存在越界的数");
break;
case -3 :
resultMap.put(-3, "对不起,购买失败,存在负数");
break;
case -4 :
resultMap.put(-4, "对不起,购买失败,存在没填写的数+越界的数");
break;
case -5 :
resultMap.put(-5, "对不起,购买失败,存在没填写的数+负数");
break;
case -6 :
resultMap.put(-6, "对不起,购买失败,存在越界的数+负数");
break;
case -7 :
resultMap.put(-7, "对不起,购买失败,存在没填写的数+越界的数+负数");
}
request.setAttribute("resultMap", resultMap);
request.setAttribute("key", station);
request.getRequestDispatcher("goodsCarResult.jsp").forward(request, response);//转发走
}
}
2、deleteGoodsCarServlet
package com.webhomework.control;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.webhomework.dao.goodsCarDao;
public class deleteGoodsCarServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = (String)request.getSession().getAttribute("name");
goodsCarDao gcd = new goodsCarDao();
gcd.deleteAllRecord(name);//这里博主偷懒了,应该发给service处理的才对
response.sendRedirect("delete.html");
}
}
3、service
博主这里写错了,其实对数据错误判断,核心算法处理,以及结果封装都应该在这里写的,这里明显少了很多东西!
package com.webhomework.service;
import java.util.ArrayList;
import com.webhomework.dao.goodsCarDao;
import com.webhomework.errorset.errorGoodsCarSet;
public class goodsCarService {
/**
* Dao层返回来的是插入的购买信息的id
* 错误情况,输入的数量超过范围,输入的数量为负数,不输入数量
*
*/
public int buyGoodsInCarService(String[] item ,String name ,ArrayList<String> numberList) {
goodsCarDao gcd = new goodsCarDao();
errorGoodsCarSet egcs = new errorGoodsCarSet();
boolean hasNullNum = false;//看是否有没填写的数
boolean transgressive = false;//看是否有越界的数
boolean hasNegativeNum = false;//看有无负数
for(int i = 0 ;i < numberList.size() ;i++) {
int maxNum = gcd.hasMaxNumberInDB(item[i]);
if(numberList.get(i).equals("")) {//填入为空
hasNullNum = true;
continue;
}
int num = Integer.parseInt(numberList.get(i));
if(num > maxNum) {
transgressive = true;
}
if(num < 0) {
hasNegativeNum = true;
}
}
if(hasNullNum || transgressive || hasNegativeNum) {
return egcs.erroeGoodsCar(hasNullNum, transgressive, hasNegativeNum);//一旦有任何一种错误就发给错误处理函数,下方会附上
}
return gcd.buyGoodsInCarDao(item, name, numberList);//数据精纯正确就发给Dao与数据库进行交互。
}
}
下面附上错误处理:
这样集中写便于管理!
package com.webhomework.errorset;
public class errorGoodsCarSet {
/**
* 处理特殊情况
* -1是存在没填写的数
* -2是存在越界的数
* -3是存在负数
* -4是存在没填写的数+越界的数
* -5是存在没填写的数+负数
* -6是存在越界的数+负数
* -7是存在没填写的数+越界的数+负数
*/
public int erroeGoodsCar(boolean hasNullNum , boolean transgressive , boolean hasNegativeNum) {
if(hasNullNum == true && transgressive == false && hasNegativeNum == false) {
return -1;
}
if(hasNullNum == false && transgressive == true && hasNegativeNum == false) {
return -2;
}
if(hasNullNum == false && transgressive == false && hasNegativeNum == true) {
return -3;
}
if(hasNullNum == true && transgressive == true && hasNegativeNum == false) {
return -4;
}
if(hasNullNum == true && transgressive == false && hasNegativeNum == true) {
return -5;
}
if(hasNullNum == false && transgressive == true && hasNegativeNum == true) {
return -6;
}
return -7;
}
}
4、dao层
得到service中的精纯数据,来与数据库交互,将得到的值返回去,千万不要进行操作,他就是交互,而不是进行逻辑操作。
package com.webhomework.dao;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.webhomework.javabeans.user;
import com.webhomework.jdbc.JDBCTools;
public class goodsCarDao {
/**
* 处理购买业务,这里只处理正确情况,错误情况见service层,处理逻辑在error里面
* 购买成功,返回1,代表购买信息已经插入表中
* 购买失败返回0,代表插入出错
* 查询单价,计算总金额,写入记录,把已经买的东西从购物车里移除,全空的车移除,返回记录的id;
* 错误情况,输入的数量超过范围,输入的数量为负数,不输入数量
*/
/**
* 处理特殊情况
* -1是存在没填写的数
* -2是存在越界的数
* -3是存在负数
* -4是存在没填写的数+越界的数
* -5是存在没填写的数+负数
* -6是存在越界的数+负数
* -7是存在没填写的数+越界的数+负数
* 大于等于1代表购买正常,返回值为record表中记录位置
*/
//dao只查询插入返回
public int buyGoodsInCarDao(String[] item ,String name ,ArrayList<String> numberList) {
JDBCTools jdbct = new JDBCTools();
ArrayList<Map<String,String>> resultMap = new ArrayList<Map<String,String>>();
ArrayList<Map<String,String>> anoResultMap = new ArrayList<Map<String,String>>();
user u = new user();
u.setName(name);
String ID = findIdInDB(u);
String sqlOne = "select price from goods where";//功能1查价格
for(int i = 0 ;i < item.length - 1 ;i++) {
String temp = " id = "+item[i]+" or";
sqlOne += temp;
}
sqlOne = sqlOne + " id = " + item[item.length - 1] +";";
System.out.println(sqlOne);
resultMap = jdbct.find(sqlOne);
//下面回service,下面是计算价格,应该回到service去
double money = 0;
System.out.println(resultMap.size());
for(int i = 0 ;i < resultMap.size() ;i++) {
double price = Double.parseDouble(resultMap.get(i).get("price"));
System.out.println(price);
double number = Double.parseDouble(numberList.get(i));
System.out.println(number);
money += price*number;
System.out.println(money);
}
//功能2把已经买的物品去掉
String goodsNum[] = {"goods_one","goods_two","goods_three","goods_four","goods_five"};
for(int i = 0 ;i < item.length ;i++) {
for(int j = 0 ;j < 5 ;j++) {
String sqlTwo = "update goods_car set "+ goodsNum[j] +" = 'null' where user_id = "+ID+" and "+ goodsNum[j] +" = "+ item[i] +";";
jdbct.update(sqlTwo);
}
}
//功能3把全是空的行删除
String sqlThree = "delete from goods_car where goods_one = 'null'and goods_two='null' and goods_three='null'and goods_four='null'and goods_five='null';";
jdbct.update(sqlThree);
//插入销售记录,返回记录ID
String sqlFour = "insert into record (name,money) values('"+ name +"','"+ money +"')";
jdbct.update(sqlFour);
String sqlFive = "select * from record";
anoResultMap = jdbct.find(sqlFive);
int mapSize = anoResultMap.size();
return Integer.parseInt(anoResultMap.get(mapSize - 1).get("id"));
}
public String findIdInDB(user u) {//功能5根据用户名字查找用户ID
JDBCTools jdbct = new JDBCTools();
List<Map<String,String>> resultList = new ArrayList<Map<String,String>>();
Map<String,String> resultMap = new HashMap<String,String>();
//未处理重名情况,处理的话把session中name换为一个List即可
String sql = "select * from user where name= '"+ u.getName() +"';";
resultList = jdbct.find(sql);
resultMap = resultList.get(0);
return resultMap.get("id");
}
public int hasMaxNumberInDB(String goodsID) {//判断是输入的数字是否超过库存,错误判断
JDBCTools jdbct = new JDBCTools();
String sql = "select num from goods where id = "+ goodsID +";";
ArrayList<Map<String,String>> resultMap = new ArrayList<Map<String,String>>();
resultMap = jdbct.find(sql);
return Integer.parseInt(resultMap.get(0).get("num"));
}
public String selectMoneyInRecord(int key) {//根据record的id号查询花了多少钱
JDBCTools jdbct = new JDBCTools();
ArrayList<Map<String ,String>> resultList = new ArrayList<Map<String ,String>>();
String sql = "select * from record where id = "+ key +";";
resultList = jdbct.find(sql);
return resultList.get(0).get("money");
}
public void deleteAllRecord(String name) {//用于一键清空某用户购物车
JDBCTools jdbct = new JDBCTools();
user u = new user();
u.setName(name);
String ID = findIdInDB(u);
String sql = "delete from goods_car where user_id = "+ ID +";";
jdbct.update(sql);
}
}
5、返回
从dao层返回数值到service 再回到servlet,在最后由servlet发给显示结果页面。
<%@page import="com.webhomework.dao.goodsCarDao"%>
<%@page import="java.util.ArrayList"%>
<%@page import="java.util.Map"%>
<%@page import="com.webhomework.jdbc.JDBCTools"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
JDBCTools jdbct = new JDBCTools();
Map<Integer,String> resultMap = (Map<Integer,String>)request.getAttribute("resultMap");
ArrayList<Map<String ,String>> resultList = new ArrayList<Map<String ,String>>();
int key = (Integer)request.getAttribute("key");
goodsCarDao gcs = new goodsCarDao();
if(resultMap.size() == 0){//看传过来的是不是代表了发生错误的代码
%>
<b>您一共消费</b>
<%=gcs.selectMoneyInRecord(key) %>//根据record表里的id号查询花了多少钱
<%
}
else{
%>
<%=resultMap.get(key) %>
<%
}
%>
<div>
<a href="body.jsp">点击回到主页面</a>
</div>
<div>
<a href="showGoods.jsp">点击添加商品</a>
</div>
<div>
<a href="goodsCar.jsp">点击继续结算商品</a>
</div>
</body>
</html>
Sum Up:
1、一定注意要将最复杂的逻辑处理放在service层,别的层一定要功能单一!
2、form表单里并不是只能放控件,其实啥都能放,一定要灵活。
3、前端在准备form:text名字的时候,一定要根据要求,尽可能方便后端接收,这样就可以减少错误处理。