Web项目系列文章推荐: |
---|
👉 JavaWeb企业实战项目(一):环境搭建-用户注册-邮件发送 |
👉 JavaWeb企业实战项目(二):用户登录-首页详情-商品分类 |
👉 JavaWeb企业实战项目(三):商品模块 |
👉 JavaWeb企业实战项目(四):订单模块 |
👉 JavaWeb企业实战项目(五):后台模块1 |
👉 待更新 |
1、任务总述
1、上传
2、利用工厂解耦
3、查询订单
4、异步加载显示详情
5、修改订单状态
6、将项目部署到LINUX上
2、实现商品上传
原理如下:
步骤实现:
1、准备工作/admin/product/list.jsp修改了addProduct()函数链接
function addProduct(){window.location.href = "${pageContext.request.contextPath}/AdminProductServlet?method=addProductUI";}
2、AdminProductServlet -> addProductUI
//获取所有分类信息
//转发到add.jsp
3、/admin/product/add.jsp中遍历分类信息
<select name="cid">
<c:forEach items="${allCats}" var="c">
<option value="${c.cid}">${c.cname}</option>
</c:forEach>
</select>
4、AdminProductServlet -> addProduct
public String addProduct(HttpServletRequest request, HttpServletResponse response) throws FileUploadException, IOException {
//执行3行语句
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List<FileItem> items = upload.parseRequest(request);
ProductService service = new ProductServiceImpl();
//创建map、Product
Map<String, String> map = new HashMap<String, String>();
Product product = new Product();
//遍历list集合
for (FileItem fileItem : items) {
if(fileItem.isFormField()){//如果是普通项
//将普通项的name属性的值作为主键,将获取到的值放入map
map.put(fileItem.getFieldName(), fileItem.getString("utf-8"));
}else{//如果是上传项
//通过fileitem获取到输入流对象,进而获取二进制数据
InputStream is = fileItem.getInputStream();
//获取绝对路径、文件名(获得uuname)、
String realPath = getServletContext().getRealPath("/products/3/");
String oldFileName = fileItem.getName();
String newFileName = UploadUtils.getUUIDName(oldFileName);
System.out.println("newFileName="+newFileName);
String dir = UploadUtils.getDir(newFileName);
System.out.println("dir="+dir);
String path = realPath+dir;
//System.out.println("realPath="+realPath+" oldFileName="+oldFileName+" dir="+dir); 测试输出
//在服务端创建一个空文件(后缀必须和上传项一致)
File dirFile = new File(path);
File file = new File(dirFile,newFileName);
//判断文件或目录是否存在,如果不存在就创建文件或者目录
if(!dirFile.exists()){dirFile.mkdirs();}
if(!file.exists()){file.createNewFile();}
//建立和空文件对应的输出流
OutputStream os = new FileOutputStream(file);
//将输入流的数据刷到输出流的数据中
IOUtils.copy(is, os);
//释放资源
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
//向map存入一个键值对的数据
map.put("pimage", "products/3"+dir+"/"+newFileName);
}
}
//设置商品属性值并存入商品
try {
BeanUtils.populate(product, map);
product.setPid(UUIDUtils.getId());
product.setpDate(new Date());
product.setPflag(0);
service.addProduct(product);
System.out.println("商品上传成功!");
response.sendRedirect("/store_v5/AdminProductServlet?method=findAllProductsWithPage&num=1");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
中途总结:
1、fileItem.isFormField返回true为普通项,且getString要有编码
2、UploadUtils.getDir获取的是8层结构目录,dir=/8/a/6/b/1/9/2/9
3、UploadUtils中,getDir方法的return值可以写num个,就是返回num层目录
4、fileItem.getName方法获得的文件名是全路径,所以要进行截取,比如
int index = fileName.lastIndexOf("\\");//获取到最后的'\'下标
if(index != -1){fileName = fileName.substring(index+1);}//如果存在'\',则截取最后文件名
5、java.util.Date和java.sql.Date 区别是:java.util.Date 类型写到数据库后存储的值可以到秒,java.sql.Date 类型的写入后只能到日期。
3、通过BeanFactory为项目解耦
我们当前的开发未实现,service层对Dao层有依赖,例如在UserServiceImpl中出现了UserDao dao = new UserDaoImpl();
这条语句
假如我们做了一个产品OA,但是我们没有办法确定客户采用什么样的数据库,此时我们需要为当前项目开发不同的数据库版本,例如为oracle,sqlserver,mysql等分别开发不同的Dao实现,但是在项目具体的运行时,我们又无法确定到底执行哪种版本
所以我们可以通过配置文件来配置dao层的各个具体的实现
Eg:在src下创建一个application.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="CategoryDao" class="cn.itcast.store.dao.daoImp.CategoryDaoImp"/>
<bean id="UserDao" class="cn.itcast.store.dao.daoImp.UserDaoImp"/>
<bean id="ProductDao" class="cn.itcast.store.dao.daoImp.ProductDaoImp"/>
</beans>
之后采用工厂来通过读取配置文件创建不同的对象来实现解耦
public static Object creatObject(String name){
//获取到Document对象
SAXReader reader = null;
//通过application.xml文件获取输入流(src)
InputStream is = null;
Document document = null;
try {
reader = new SAXReader();
is = BeanFactory.class.getClassLoader().getResourceAsStream("application.xml");
document = reader.read(is);
//通过Document对象获取根节点beans
Element rootElement = document.getRootElement();
//通过根节点获取到根节点下所有子节点bean,返回集合
List<Element> list = rootElement.elements();
//遍历集合,判断每个元素上的id的值是否和当前name一致
for (Element element : list) {
String id = element.attributeValue("id");
if(id.equals(name)){//如果一致,获取到当前元素上class的属性值
String className = element.attributeValue("class");
//利用class值通过反射创建对象并返回
Class clazz = Class.forName(className);
return clazz.newInstance();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
工厂模式解耦的好处:
1、不对用户透露Dao层实现源码
2、如果用户需求的数据库有变,直接修改BeanFactory中一行即可
3、前提是所有版本数据库Dao层都有实现
4、查询订单
原理如下:
步骤实现:
1、准备工作 /admin/left.jsp
d.add('010501','0105','订单管理',
d.add('010501','0105','订单管理','${pageContext.request.contextPath}/AdminOrderServlet?method=findOrders','','mainFrame');
d.add('010502','0105','未付款的订单','${pageContext.request.contextPath}/AdminOrderServlet?method=findOrders&state=1','','mainFrame');
d.add('010503','0105','已付款订单','${pageContext.request.contextPath}/AdminOrderServlet?method=findOrders&state=2','','mainFrame');
d.add('010504','0105','已发货的订单','${pageContext.request.contextPath}/AdminOrderServlet?method=findOrders&state=3','','mainFrame');
d.add('010505','0105','已完成的订单','${pageContext.request.contextPath}/AdminOrderServlet?method=findOrders&state=4','','mainFrame');
2、AdminOrderServlet -> findOrders
public String findAllOrders(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取订单状态
String state = request.getParameter("state");
OrderService service = new OrderServiceImpl();
List<Order> orders = null;
/*如果获取不到状态获取全部订单
如果可以获取到状态,查询不同状态的订单*/
if(null == state){
orders = service.findAllOrders();
}else{
orders = service.findAllOrders(state);
}
//将订单放入request
request.setAttribute("orders", orders);
//转发/admin/order/list.jsp
return "/admin/order/list.jsp";
}
3、OrderService -> OrderDao
//OrderDao
@Override
public List<Order> findAllOrders() throws Exception {
String sql = "select * from orders";
return qr.query(sql, new BeanListHandler<Order>(Order.class));
}
@Override
public List<Order> findAllOrders(String state) throws Exception {
String sql = "select * from orders where state = ?";
return qr.query(sql, new BeanListHandler<Order>(Order.class),state);
}
4、/admin/order/lis.jsp
获取全部订单信息完成响应
总结:
本功能特点:多个链连共享相同的代码段
5、异步加载显示订单详情
原理如下:
步骤实现:
1、将当前功能要实现最终效果先实现(静态效果)
在*订单详情* 按钮下增加table标签,内部无内容
<input type="button" value="订单详情" id="${o.oid}" class="orderInfo"/> <table width="100%" cellspacing="0" cellpadding="1" rules="all" bordercolor="gray" border="1" id="DataGrid1" style="BORDER-RIGHT: gray 1px solid; BORDER-TOP: gray 1px solid; BORDER-LEFT: gray 1px solid; WIDTH: 100%; WORD-BREAK: break-all; BORDER-BOTTOM: gray 1px solid; BORDER-COLLAPSE: collapse; BACKGROUND-COLOR: #f5fafe; WORD-WRAP: break-word"> </table>
2、用户点击订单详情按钮,向服务端发起ajax请求,向服务端传递订单id
- 获取单击按钮事件
$(".orderInfo").click(function()
- 实现按钮切换(先获得value),修改value
这里的注意点是,value用this.value可以直接获取,但id就不可用直接写this(在下面的步骤有提到) - 开始实现剩余功能,(得到其他所有的var)
1、这里考察了function中data数组的书写:{"key1":"value1","key2":"value2"}
2、input的next标签不可直接用this.next();直接获取,否则直接无响应,正确写法应该是$(this).next();
3、同上原理,input的id属性也只能用$(this).attr("id");
来获取
4、标签元素添加内容用append(),清空内容用html("") - 异步请求代码如下:
$(".orderInfo").click(function(){ //alert("0"); 测试成功 var title = this.value; var obj = {"method":"findOrderByOidWithAjax","oid":$(this).attr("id")}; //alert("1"); 测试成功 var url = "/store_v5/AdminOrderServlet"; var $table = $(this).next(); //alert("3"); 测试成功 if(title=="订单详情"){ this.value="关闭详情"; $.post(url, obj, function(data) { //alert("2"); 测试成功 var th = "<tr><td align='center' width='30%'>编号</td><td align='center' width='50%'>商品名</td><td align='center' width='10%'>商城价</td><td align='center' width='10%'>数量</td><td align='center' width='15%'>总计</td></tr>"; $table.append(th); $.each(data,function(i, item) { var td = "<tr><td align='center' width='30%'>"+item.itemid+"</td><td align='center' width='50%'>"+item.product.pname+"</td><td align='center' width='10%'>"+item.product.shop_price+"</td><td align='center' width='10%'>"+item.quantity+"</td><td align='center' width='15%'>"+item.total+"</td></tr>"; $table.append(td); }) //alert("4"); 测试成功 }, "json"); }else{ $table.html(""); this.value="订单详情"; } });
3、服务端获取到订单ID,查询这个订单下所有的订单项以及订单项对应的商品信息,返回集合
4、将返回的集合转换为JSON格式字符串,响应到客户端
5、调试,排除2端错误
6、在客户端获取到服务端想回会的JSON格式的数据,将这些数据绑定在页面上
//AdminOrderServlet
public String findOrderByOidWithAjax(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取到oid
String oid = request.getParameter("oid");
//查看这个订单下所有的订单项以及对应的商品信息,返回集合
OrderService service = new OrderServiceImpl();
Order order = service.findOrderByOidWithAjax(oid);
//将返回的集合以JSON格式字符串,响应到客户端
String json = JSONArray.fromObject(order.getOrderitem()).toString();
//响应到客户端
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(json);
//返回Null
return null;
}
总结:
1、Ajax功能,注意思路,开发步骤
2、JSONObject.fromObject的时候,出现“There is a cycle in the hierarchy”异常,原因是在使用service的findOrderByOid时,产生了自包含,删除Dao层对应行即可
6、修改订单状态
原理如下:
步骤实现:
1、准备工作 admin/order/list.jsp
<a href="/store_v5/AdminOrderServlet?method=updateOrderByOid&oid=${o.oid}">发货</a>
2、AdminOrderServlet -> updateOrderByOid
public String updateOrderByOid(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取到oid
String oid = request.getParameter("oid");
//根据订单id查询订单
OrderService service = new OrderServiceImpl();
Order order = service.findOrderByOid(oid);
//修改订单状态
order.setState(3);
//修改订单信息
service.updateOrder(order);
//重定向到查询已发货订单
response.sendRedirect("/store_v5/AdminOrderServlet?method=findAllOrders&state=3");
return null;
}
3、service -> dao
7、将项目部署到linux系统上
1、导出SQL语句
2、启动linux,利用CTR连接
3、修改2个配置文件中的参数 c3p0.xml jedisUtils
4、导出项目,以war包形式
5、启动tomcat
6、利用sqlyong连接linux下的mysql,恢复数据
7、启动redis
8、利用fileziller将项目发送到linux上tomcat下的webapp下