后台添加商品和添加到购物车

前端页面

	<script type="text/javascript">
  		function checkData(){
  			var price = document.getElementsByName("price")[0].value;
  			if(isNaN(price)){
  				alert("单价必须是数字!");
  				document.getElementsByName("price")[0].value = "";
  				return false;
  			}else if(price<=0){
	  			alert("单价必须大于0!")
	  			document.getElementsByName("price")[0].value = "";
	  			return false;
  			}else{
  				return true;
  			}
  		}
  	</script>
  </head>
  <body style="text-align: center;">
  	<h1>Estore_添加商品</h1><hr>
  	<form action="/AddprodServlet" method="POST" enctype="multipart/form-data" onsubmit="return checkData()">
  		<table border="1">
  			<tr>
  				<td>商品名称</td>
  				<td><input type="text" name="name"/></td>
  			</tr>
  			<tr>
  				<td>单价</td>
  				<td><input type="text" name="price"/></td>
  			</tr>
  			<tr>
  				<td>商品种类</td>
  				<td>
					<select name="category">
						<option value="电子数码">电子数码</option>
						<option value="图书杂志">图书杂志</option>
						<option value="床上用品">床上用品</option>
						<option value="日用百货">日用百货</option>
						<option value="大型家电">大型家电</option>
						<option value="家用武器">家用武器</option>
					</select>
				</td>
  			</tr>
  			<tr>
  				<td>库存数量</td>
  				<td><input type="text" name="pnum"/></td>
  			</tr>
  			<tr>
  				<td>商品图片</td>
  				<td><input type="file" name="file1"/></td>
  			</tr>
  			<tr>
  				<td>描述信息</td>
  				<td><textarea name="description" rows="6" cols="40"></textarea></td>
  			</tr>
  			<tr>
  				<td colspan="2"><input type="submit" value="添加商品"></td>
  			</tr>
  		</table>
  	</form>

1.因为其中含有文件上传,所以文件类型multipart/form-data.2.文件上传项必须有name.3.POST提交

其他没什么了,这里做了个表单验证,不过只验证了价格。用了个onsubmit,提交时触动方法,(注意这个方法是需要返回值)

所以说return  checkData(),为true表单才会提交。

提交后,到servelt进行封装,但是这里用到了文件上传,比较复杂。

AddprodServlet:

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ProdService service = BasicFactory.getFactory().getInstance(ProdService.class);
		
		try {
			String encode = this.getServletContext().getInitParameter("encode");
			Map<String, String> paramMap = new HashMap<String,String>();
			//1.上传图片
			DiskFileItemFactory factory = new DiskFileItemFactory();
			factory.setSizeThreshold(1024*100);
			factory.setRepository(new File(this.getServletContext().getRealPath("WEB-INF/temp")));
			
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			fileUpload.setHeaderEncoding(encode);
			fileUpload.setFileSizeMax(1024*1024*1);
			fileUpload.setSizeMax(1024*1024*10);
			
			if(!fileUpload.isMultipartContent(request)){
				throw new RuntimeException("请使用正确的表单进行上传!");
			}
	
			List<FileItem> list = fileUpload.parseRequest(request);
			for(FileItem item : list){
				if(item.isFormField()){
					//普通字段
					String name = item.getFieldName();
					String value = item.getString(encode);
					paramMap.put(name, value);
				}else{
					//文件上传项
					String realname = item.getName();
					String uuidname = UUID.randomUUID().toString()+"_"+realname;

					String hash = Integer.toHexString(uuidname.hashCode());
					String upload = this.getServletContext().getRealPath("WEB-INF/upload");
					String imgurl = "/WEB-INF/upload";
					for(char c : hash.toCharArray()){
						upload+="/"+c;
						imgurl+="/"+c;
					}
					imgurl +="/"+uuidname;
					paramMap.put("imgurl", imgurl);
					
					File uploadFile = new File(upload);
					if(!uploadFile.exists())
						uploadFile.mkdirs();
					
					InputStream in = item.getInputStream();
					OutputStream out = new FileOutputStream(new File(upload,uuidname));
					
					IOUtils.In2Out(in, out);
					IOUtils.close(in, out);
					
					item.delete();
					
					//--生成缩略图
					PicUtils picu = new PicUtils(this.getServletContext().getRealPath(imgurl));
					picu.resizeByHeight(140);
				}
			}
			
			//2.调用Service中提供的方法,在数据库中添加商品
			Product prod = new Product();
			BeanUtils.populate(prod, paramMap);
			service.addProd(prod);
			
			//3.提示成功,回到主页
			response.getWriter().write("添加商品成功!3秒回到主页..");
			response.setHeader("Refresh", "3;url=/index.jsp");
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

因为含有文件,所以不能向往常一样直接用requestMap封装。自己新建一个map,我们必须得先将文件下载保存到确定的路径。

通过DiskFileItemFactory 建立factory,用它创建个fileUpload,然后解析request,fileUpload.parseRequest(request);

得到一个list集合,然后进行判断。普通属性就直接丢进去。文件的话,安照上面来。主要讲下过程。

String hash = Integer.toHexString(uuidname.hashCode());
                    String upload = this.getServletContext().getRealPath("WEB-INF/upload");
                    String imgurl = "/WEB-INF/upload";
                    for(char c : hash.toCharArray()){
                        upload+="/"+c;
                        imgurl+="/"+c;
                    }

                 imgurl +="/"+uuidname;

按照文件名用哈希码打散目录。最后的upload是文件夹,imgurl指向的是文件,所以把他放进map中。然后用流读取文件。

然后关闭流后,删除临时目录的文件。生成缩略图,就是改变图片的大小,这个工具类里面有很多缩放的方法。

然后将改变了大小的文件输出到原来的文件夹。文件发生了改变,所以使用缩略图时,还得更改图片名字。然后就是常规的添加数据库,转发了。

service层:需要生成id,因为id不是自增,需要手动设置,uuid。

ProdDao dao = BasicFactory.getFactory().getInstance(ProdDao.class);
	public void addProd(Product prod) {
		prod.setId(UUID.randomUUID().toString());
		dao.addProd(prod);
	}

dao层就不写了。

添加购物车:AddCarServlet

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ProdService service = BasicFactory.getFactory().getInstance(ProdService.class);
		//1.根据id查找出要购买的商品
		String id = request.getParameter("id");
		Product prod = service.findProdById(id);
		//2.向cartmap中添加这个商品,如果之前没有这个商品,则添加并将数量设置为1,如果已经有过这个商品,数量+1
		if(prod==null){
			throw new RuntimeException("找不到该商品!");
		}else{
			Map<Product,Integer> cartmap = (Map<Product, Integer>) request.getSession().getAttribute("cartmap");
			cartmap.put(prod, cartmap.containsKey(prod)?cartmap.get(prod)+1 : 1);
		}
		//3.重定向到购物车页面进行展示
		response.sendRedirect("/cart.jsp");
	}

这个购物车的servelt,写的比上一个牛逼。都没有新建个map,直接从session域中取出来了。因为啊

新建一个session监听器,用于监听session建立和销毁。

public class MyHSessionListener implements HttpSessionListener {

	public void sessionCreated(HttpSessionEvent se) {
		se.getSession().setAttribute("cartmap", new LinkedHashMap<Product, Integer>());
	}

	public void sessionDestroyed(HttpSessionEvent se) {

	}

}



<!-- 监听器配置开始 -->
		<listener>
			<listener-class>com.itheima.listener.MyHSessionListener</listener-class>
		</listener>
	<!-- 监听器配置结束 -->

在session一建立,就建立一个map。说明只要用户进来了,就在session域中给他建了个购物车。用户退出,那么map也没了。

好好看看上面添加到购物车代码,简直完美。(注意,这个map,你们认为map是怎么判断存键值的?这里我们使用对象当做键,那么只要对象不一样,他会根据哈希码来算,就会当做一个新的对象存入。所以这里我们不能把整个对象用哈希码算)

像下面那样,只用id来作为判断。否则,咱们每添加一个商品,就会新建一个键值对。如果这样了,就不会。

public void setDescription(String description) {
		this.description = description;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Product other = (Product) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

cart.jsp:这段代码也是耐人寻味。

 <head>
  	<script type="text/javascript">
  		function changeNum(id,obj,oldnum){
  			if(!/^[1-9]\d*$/.test(obj.value)){
  				alert("购买数量必须为正整数!");
  				obj.value=oldnum;
  				return;
  			}
  			window.location.href="/ChangeCartServlet?id="+id+"&buynum="+obj.value;
  		}
  	</script>
  </head>
  <body style="text-align: center;" >
  	<h1>我的购物车</h1>
  	<div align="right">
  		<a href="/ProdListServlet">继续购物</a>
  		<a href="/ClearCartServlet">清空购物车</a>
  		<a href="#"><img src="/img/gotoorder.bmp"/></a>
  	</div>
  	
  	<hr>
  	<c:if test="${empty sessionScope.cartmap}">
  		<h2><a href="/ProdListServlet">购物车空空如也,请先去挑点东西吧~~~</a></h2>
  	</c:if>
  	<c:if test="${not empty sessionScope.cartmap}">
		<table width="100%" border="1" style="text-align: center">
			<tr>
				<th>缩略图</th>
				<th>商品名称</th>
				<th>商品种类</th>
				<th>商品单价</th>
				<th>购买数量</th>
				<th>库存状态</th>
				<th>总价</th>
				<th>删除</th>
			</tr>
			<c:set var="money" value="0" />
			<c:forEach items="${sessionScope.cartmap}" var="entry">
				<tr>
					<td><img src="/ImgServlet?imgurl=${entry.key.imgurls }"/></td>
					<td>${entry.key.name }</td>
					<td>${entry.key.category }</td>
					<td>${entry.key.price }元</td>
					<td><input type="text" value="${entry.value }" style="width: 30px" onchange="changeNum('${entry.key.id }',this,${entry.value })"/>件</td>
					<td>
						<c:if test="${entry.value<=entry.key.pnum}">
							<font color="blue">有货</font>
						</c:if>
						<c:if test="${entry.value>entry.key.pnum}">
							<font color="red">缺货</font>
						</c:if>
					</td>
					<td>
						${entry.key.price * entry.value }元
						<c:set var="money" value="${money + entry.key.price * entry.value }"/>
					</td>
					<td>
						<a href="/DelCartServlet?id=${entry.key.id }">删除</a>
					</td>
				</tr>
			</c:forEach>
		</table>
		<div align="right">
			<font color="red" size=6">总价:${money }元</font>
		</div>
  	</c:if>

亮点知识一:

<c:if test="${empty sessionScope.cartmap}">
          <h2><a href="/ProdListServlet">购物车空空如也,请先去挑点东西吧~~~</a></h2>
      </c:if>
      <c:if test="${not empty sessionScope.cartmap}">

看着两段代码,啊,上面这段牛逼多了。

<c:if test="${sessionScope.user == null}">
          欢迎光临,游客
          <a href="/regist.jsp">注册</a>
          <a href="/login.jsp">登录</a>
      </c:if>
      <c:if test="${sessionScope.user != null}">

二:<c:set var="money" value="0" />

<c:set var="money" value="${money + entry.key.price * entry.value }"/>

这个set方法,就是开辟一个money域,每次都是从里面去,相当于静态变量。所以最后可以取出总价钱。每次循环都会叠加

注意这个map的遍历取值方法。

三:<td><input type="text" value="${entry.value }" style="width: 30px" onchange="changeNum('${entry.key.id }',this,${entry.value })"/>件</td>

这里有点牛逼。修改数量的同时,用正则验证数字正确性,还用请求servlet去修改购物车map中数量。每次输入框的值都调用函数  用了 onchange 传入了三个参数,分别是商品id,当前dom对象,和商品数量。

function changeNum(id,obj,oldnum){
              if(!/^[1-9]\d*$/.test(obj.value)){
                  alert("购买数量必须为正整数!");
                  obj.value=oldnum;
                  return;
              }
              window.location.href="/ChangeCartServlet?id="+id+"&buynum="+obj.value;
          }

首先正则表达式验证了输入商品数量是否符合规范,不符合规范的,把修改的值还原到原来的值。之后请求servlet。

记住这个  window.locatin.href="/",发送一个请求。

servlet如下:就是修改了一下数量。

public class ChangeCartServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ProdService service = BasicFactory.getFactory().getInstance(ProdService.class);
		//1.获取要删除的id,根据id查找出商品
		String id = request.getParameter("id");
		Product prod = service.findProdById(id);
		//2.获取购物车,修改数量
		Map<Product,Integer> cartmap = (Map<Product, Integer>) request.getSession().getAttribute("cartmap");
		cartmap.put(prod, Integer.parseInt(request.getParameter("buynum")));
		//3.重定向回到购物车页面
		response.sendRedirect("/cart.jsp");
	}

四:展示的时候使用的缩略图<td><img src="/ImgServlet?imgurl=${entry.key.imgurls }"/></td>

请求servlet,还记得开始我们说的吗?我们存的地址啊,不是缩略图的地址,因为缩略图是在原有的文件名上做了改动的。

但是他的改动不大,一般都是在后面加上点字母    比如这里 加的_s.

靠,他这招厉害。一般像这种需要在中间就加入值的,我们必须得分割字符加进去吧。靠他居然在get方法里面加。

public String getImgurl() {
		return imgurl;
	}
	public String getImgurls() {
		return imgurl.substring(0,imgurl.lastIndexOf("."))
						+"_s"
							+imgurl.substring(imgurl.lastIndexOf("."));
	}

为什么他又新建了一个imgurls,这个和imgurl不同的是,他加了_s.

现在大家就疑惑了,怎么取的到呢?entry.key.imgurls ,看他取的是什么?靠,差点忘了EL表达式底层是用get方法取的值。

这思路没谁了。

删除购物车商品:

这个就更简单了。直接根据id,查出商品,直接删除就好了

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ProdService service = BasicFactory.getFactory().getInstance(ProdService.class);
		//1.获取要删除的id,根据id查找出商品
		String id = request.getParameter("id");
		Product prod = service.findProdById(id);
		//2.获取购物车,删除该商品
		Map<Product,Integer> cartmap = (Map<Product, Integer>) request.getSession().getAttribute("cartmap");
		cartmap.remove(prod);
		//3.重定向回到购物车页面
		response.sendRedirect("/cart.jsp");
	}

购物车模块结束。

完!!!!!

猜你喜欢

转载自blog.csdn.net/BadRibbit/article/details/81876633