文章目录

  • 1、任务总述
  • 2、实现商品上传
  • 3、通过BeanFactory为项目解耦
  • 4、查询订单
  • 5、异步加载显示订单详情
  • 6、修改订单状态
  • 7、将项目部署到linux系统上


1、任务总述

1、上传
2、利用工厂解耦
3、查询订单
4、异步加载显示详情
5、修改订单状态
6、将项目部署到LINUX上

2、实现商品上传

原理如下:

java后端书架 java后端项目实战_java后端书架


步骤实现:

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、查询订单

原理如下:

java后端书架 java后端项目实战_java_02


步骤实现:

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、异步加载显示订单详情

原理如下:

java后端书架 java后端项目实战_工厂模式_03


步骤实现:

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、修改订单状态

原理如下:

java后端书架 java后端项目实战_java_04


步骤实现:

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下