Java Web基础入门第八十六讲 在线网上书店(一)——搭建开发环境

Java Web基础入门 专栏收录该内容
115 篇文章 21 订阅

前言

为了巩固之前所学Java Web基础,特做一个还算是比较完整的小项目——在线网上书店。

成果图

在线网上书店这个项目包含了两个部分,前台和后台。前台用于向用户显示商品(这里是书籍)信息,如下图所示。
在这里插入图片描述
后台由管理员进行管理,后台分为分类管理模块、图书管理模块、订单管理模块以及数据库管理模块等4个模块,如下图所示。
在这里插入图片描述

搭建开发环境

导入开发包和创建包结构

在Eclipse中新创建一个mybookstore的项目,导入项目所需要的开发包(jar包),创建项目所需要的包,在Java Web开发中,架构的层次是以包的形式体现出来的。
在这里插入图片描述
在这里插入图片描述
以上就是根据此项目的实际情况创建的包,可能还需要创建其他的包,这个得根据项目的需求来定了。

后台分帧页面

在WebRoot根目录下新建一个manager.jsp页面,这个页面代表后台首页,而且该页面是一个分帧页面,分帧的代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>在线网上书店后台管理页面</title>
</head>
<frameset rows="18%,*">
	<frame src="${pageContext.request.contextPath }/manager/head.jsp" name="head" />
	<frameset cols="15%,*">
		<frame src="${pageContext.request.contextPath }/manager/left.jsp" name="left" />
		<frame src="" name="right" />
	</frameset>
</frameset>
</html>

我们还要在WebRoot根目录下新建一个manager目录,用于保存后台相关的一系列jsp页面。由于后台首页包含有head.jsp和left.jsp这两个页面,所以,还要在manager目录中新建出这两个页面。

  • head.jsp页面的内容如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>在线网上书店后台管理页面的页头部分</title>
    </head>
    <body style="text-align: center;">
    	<h1>在线网上书店后台管理</h1>
    </body>
    </html>
    
  • left.jsp页面的内容如下:

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
      <head>
        <title>后台左侧导航页面</title>
        
        <style type="text/css">
          .dc { 
          		display: none; 
          		margin-left: 10px;
          	  }
    	</style>
    	
    	<script language="javascript">
    	      function test(e) {
    	    	  	var div = document.getElementById(e);
    	            div.style.display = div.style.display == 'block' ? 'none' : 'block' ;       
    	      }
    	</script>
      </head>
      
      <body>
        <ul>
        	<li>
        		<a href="#" onclick="test('div1')">分类管理
        			<div class="dc" id="div1">
    	    			<a href="#"  target="right">添加分类</a><br/>
    	    			<a href="#"  target="right">查看分类</a><br/>
    	    		</div>
        		</a>
        	</li>
        	
        	<br/><br/>
        	
        	<li>
        		<a href="#" onclick="test('div2')">图书管理
        			<div class="dc" id="div2">
        				<a href="#"  target="right">添加图书</a><br/>
        				<a href="#"  target="right">查看图书</a>
    	    		</div>
        		</a>
        	</li>
        	
        	<br/><br/>
        	
        	<li>
        		<a href="#" onclick="test('div3')">订单管理
    	    		<div class="dc" id="div3">
    	    			<a href="#"  target="right">待处理订单</a><br/>
    	    			<a href="#"  target="right">已发货订单</a><br/>
    	    		</div>
        		</a>
        	</li>
        	
        	<br/><br/>
        	
        	<li>
        		<a href="#" onclick="test('div4')">数据库管理
    	    		<div class="dc" id="div4">
    	    			<a href="#"  target="right">数据库备份</a><br/>
    	    			<a href="#"  target="right">数据库恢复</a><br/>
    	    		</div>
        		</a>
        	</li>
        </ul>
      </body>
    </html>
    

这样,后台分帧页面的显示效果如下:
在这里插入图片描述

前台分帧页面

在WebRoot根目录下新建一个client目录,用于保存前台相关的一系列jsp页面。紧接着在client目录中创建前台首页——index.jsp。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>前台首页</title>
</head>
<body style="text-align: center;">
	<div id="container">
		<div id="head">
			<!-- 静态引入 -->
			<%@include file="/client/head.jsp" %>
		</div>
		
		<div id="main">
			......
		</div>
	</div>
</body>
</html>

由于在前台首页中静态引入了head.jsp页面,所以,还要在client目录中新建出这个页面。

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<h1>网上书店</h1>
<br/>
<br/>
<hr>

这样,前台分帧页面的显示效果如下:
在这里插入图片描述
先把前台和后台分帧的页面架子给搭起来,后面在此基础上进行修修改改!

创建项目所需的库

create database bookstore;
use bookstore;

创建一些全局的工具类和过滤器

在cn.liayun.utils包中创建一个WebUtils工具类,该工具类的功能就是封装客户端提交的表单数据到一个JavaBean中。

package cn.liayun.utils;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.BeanUtils;

//主要把请求数据封装到一个JavaBean中
public class WebUtils {
	
	public static <T> T request2Bean(HttpServletRequest request, Class<T> beanClass) {
		try {
			T bean = beanClass.newInstance();
			Map<String, String[]> map = request.getParameterMap();
			BeanUtils.populate(bean, map);
			return bean;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}

为了业务逻辑层和数据访问层之间的解耦,我们还应使用工厂设计模式来编写一下DaoFactory类来实现。于是,新建一个cn.liayun.factory包,在包中创建一个Dao工厂,即DaoFactory类,该类一般要设计成单例的。

package cn.liayun.factory;

import java.io.InputStream;
import java.util.Properties;

public class DaoFactory {
	
	private static Properties prop = new Properties();

	private DaoFactory() {
		try {
			InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("cn/liayun/factory/dao.properties");
			prop.load(in);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		
	}
	private static final DaoFactory instance = new DaoFactory();
	public static DaoFactory getInstance() {
		return instance;
	}
	
	public <T> T createDao(Class<T> interfaceClass) {
		try {
			String key = interfaceClass.getSimpleName();
			String className = prop.getProperty(key);
			return (T) Class.forName(className).newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
}

紧接着,在cn.liayun.factory包下创建一个dao.properties文件,该配置文件的内容如下:

CategoryDao=cn.liayun.dao.impl.CategoryDaoImpl
BookDao=cn.liayun.dao.impl.BookDaoImpl
UserDao=cn.liayun.dao.impl.UserDaoImpl
OrderDao=cn.liayun.dao.impl.OrderDaoImpl
DbBackDao=cn.liayun.dao.impl.DbBackDaoImpl

接下来,我们要编写一个用于处理全站中文乱码的过滤器CharacterEncodingFilter。

package cn.liayun.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CharacterEncodingFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		
		request.setCharacterEncoding("UTF-8");
		
		chain.doFilter(request, response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}

}

紧接着,就要在web.xml文件中配置CharacterEncodingFilter过滤器了。

<filter>
	<filter-name>CharacterEncodingFilter</filter-name>
	<filter-class>cn.liayun.web.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>CharacterEncodingFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

我们还要编写一个html转义过滤器(HtmlFilter),代码如下:

package cn.liayun.web.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;

public class HtmlFilter implements Filter {

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// TODO Auto-generated method stub

	}

	@Override
	public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
			throws IOException, ServletException {
		
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;

		//request.getParameter("");
		chain.doFilter(new MyRequest(request), response);
	}

	@Override
	public void destroy() {
		// TODO Auto-generated method stub

	}
	
	class MyRequest extends HttpServletRequestWrapper {
		
		private HttpServletRequest request;

		public MyRequest(HttpServletRequest request) {
			super(request);
			this.request = request;
		}

		@Override
		public String getParameter(String name) {
			String value = this.request.getParameter(name);
			return filter(value);
		}
		
		public String filter(String message) {

	        if (message == null)
	            return (null);

	        char content[] = new char[message.length()];
	        message.getChars(0, message.length(), content, 0);
	        StringBuilder result = new StringBuilder(content.length + 50);
	        for (int i = 0; i < content.length; i++) {
	            switch (content[i]) {
	            case '<':
	                result.append("&lt;");
	                break;
	            case '>':
	                result.append("&gt;");
	                break;
	            case '&':
	                result.append("&amp;");
	                break;
	            case '"':
	                result.append("&quot;");
	                break;
	            default:
	                result.append(content[i]);
	            }
	        }
	        return (result.toString());

	    }
		
	}

}

紧接着,就要在web.xml文件中配置HtmlFilter过滤器了。

<filter>
	<filter-name>HtmlFilter</filter-name>
	<filter-class>cn.liayun.web.filter.HtmlFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>HtmlFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

《Java Web基础入门第六十二讲 JDBC应用中的事务管理》这篇文章中,为了更加优雅地处理事务,我们使用了ThreadLocal类改造过数据库连接工具类JdbcUtils。所以,还得在cn.liayun.utils包中创建这样一个数据库连接工具类JdbcUtils。

package cn.liayun.utils;

import java.sql.Connection;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JdbcUtils {
	
	private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
	
	private static DataSource ds;
	
	static {
		ds = new ComboPooledDataSource();
	}
	
	public static DataSource getDataSource() {
		return ds;
	}
	
	public static Connection getConnection() {
		try {
			//首先得到当前线程上绑定的连接
			Connection conn = tl.get();
			if (conn == null) {
				conn = ds.getConnection();//如果当前线程上没有绑定一个连接,则从数据库连接池拿一个连接
			}
			tl.set(conn);//把连接绑定到当前线程上去
			return conn;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void startTransaction() {
		try {
			Connection conn = getConnection();
			conn.setAutoCommit(false);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void commitTransaction() {
		try {
			Connection conn = getConnection();
			if (conn != null) {
				conn.commit();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	public static void closeConn() {
		Connection conn = null;
		try {
			conn = getConnection();
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			/*
			if (conn != null) {
				tl.remove();
			}
			*/
			tl.remove();//千万要注意,解除当前线程上绑定的连接(从ThreadLocal容器中移除掉对应当前线程上的连接)
		}
	}
	
}

由于以上工具类使用了C3P0数据源,所以要在类目录下加入C3P0的配置文件,即c3p0-config.xml,该配置文件中的内容如下:

<c3p0-config>
	<!-- 
		C3P0的缺省(默认)配置,
		如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource();”这样写就表示使用的是C3P0的缺省(默认)配置信息来创建数据源
	-->
	<default-config>
		<property name="driverClass">com.mysql.jdbc.Driver</property>
		<property name="jdbcUrl">jdbc:mysql://localhost:3306/bookstore</property>
		<property name="user">root</property>
		<property name="password">liayun</property>
		
		<property name="initialPoolSize">10</property>
		<property name="maxIdleTime">30</property><!-- 最大空闲时间 -->
		<property name="maxPoolSize">20</property>
		<property name="minPoolSize">5</property>
		<property name="maxStatements">200</property>
	</default-config>

	<!-- 
		C3P0的命名配置,
		如果在代码中“ComboPooledDataSource ds = new ComboPooledDataSource("mysql");”这样写就表示使用的是name为mysql的配置信息来创建数据源
	-->
	<named-config name="mysql">
		<property name="acquireIncrement">50</property>
		<property name="initialPoolSize">100</property>
		<property name="minPoolSize">50</property>
		<property name="maxPoolSize">1000</property>

		<!-- intergalactoApp adopts a different approach to configuring statement 
			caching -->
		<property name="maxStatements">0</property>
		<property name="maxStatementsPerConnection">5</property>
	</named-config>
</c3p0-config>

也是在《Java Web基础入门第六十二讲 JDBC应用中的事务管理》这篇文章中,我们漏讲了一个事务过滤器,如果使用了事务过滤器,那么一次请求范围内的所有操作都将在一个事务里面了,如下图所示。
在这里插入图片描述
如果事务过滤器是像下面这样编写的,那么会有什么问题呢?
在这里插入图片描述
读者试着思考一下,如果访问的是网站首页——index.jsp,那么该事务过滤器拦截下来之后,势必也要获取连接并开启事务,然后把连接绑定到当前线程上。如此一来,效率势必要差很多。更加合适的做法就是把获取连接、开启事务的操作延迟到第一次访问数据库时,而不是说,我一上来就帮你获取连接、开启事务,这样子做,效率上要好一点。因此,该事务过滤器要修改为:
在这里插入图片描述
试想,当我们在后续编写dao层的代码时,一上来势必会调用JdbcUtils类的getConnection方法获取一个连接,而且这个方法要确保获取到的是一个开启事务的连接。因此,还要修改JdbcUtils类的getConnection方法。
在这里插入图片描述
千万不要忘了在web.xml文件中配置TransactionFilter事务过滤器。

<filter>
	<filter-name>TransactionFilter</filter-name>
	<filter-class>cn.liayun.web.filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>TransactionFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

至此,在线网上书店项目的环境总算是搭建好了!

  • 4
    点赞
  • 2
    评论
  • 8
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 猿与汪的秘密 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值