前端页面
<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" οnchange="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");
}
购物车模块结束。