目录
温故知新,学有所获~~书城项目是整个Javaweb阶段的实操项目
Javaweb书城项目资源
第一阶段:表单验证
需求
流程
分为购物车,后台管理,订单,用户登录注册模块
3.在register.html中实现代码逻辑
代码实现
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面</title>
<link type="text/css" rel="stylesheet" href="../../static/css/style.css" >
<script type="text/javascript" src="../../static/script/jquery-1.7.2.js"></script>
<script type="text/javascript">
// 页面加载完成之后
$(function () {
// 给注册绑定单击事件
$("#sub_btn").click(function () {
// 验证用户名:必须由字母,数字下划线组成,并且长度为5到12位
//1 获取用户名输入框里的内容
var usernameText = $("#username").val();
//2 创建正则表达式对象
var usernamePatt = /^\w{5,12}$/;
//3 使用test方法验证
if (!usernamePatt.test(usernameText)) {
//4 提示用户结果
$("span.errorMsg").text("用户名不合法!");
//禁止跳转
return false;
}
// 验证密码:必须由字母,数字下划线组成,并且长度为5到12位
//1 获取用户名输入框里的内容
var passwordText = $("#password").val();
//2 创建正则表达式对象
var passwordPatt = /^\w{5,12}$/;
//3 使用test方法验证
if (!passwordPatt.test(passwordText)) {
//4 提示用户结果
$("span.errorMsg").text("密码不合法!");
return false;
}
// 验证确认密码:和密码相同
//1 获取确认密码内容
var repwdText = $("#repwd").val();
//2 和密码相比较
if (repwdText != passwordText) {
//3 提示用户
$("span.errorMsg").text("确认密码和密码不一致!");
return false;
}
// 邮箱验证:xxxxx@xxx.com
//1 获取邮箱里的内容
var emailText = $("#email").val();
//2 创建正则表达式对象
var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
//3 使用test方法验证是否合法
if (!emailPatt.test(emailText)) {
//4 提示用户
$("span.errorMsg").text("邮箱格式不合法!");
return false;
}
// 验证码:现在只需要验证用户已输入。因为还没讲到服务器。验证码生成。
var codeText = $("#code").val();
//去掉验证码前后空格
// alert("去空格前:["+codeText+"]")
codeText = $.trim(codeText);
// alert("去空格后:["+codeText+"]")
if (codeText == null || codeText == "") {
//4 提示用户
$("span.errorMsg").text("验证码不能为空!");
return false;
}
// 去掉错误信息
$("span.errorMsg").text("");
});
});
</script>
<style type="text/css">
.login_form{
height:420px;
margin-top: 25px;
}
</style>
</head>
<body>
<div id="login_header">
<img class="logo_img" alt="" src="../../static/img/logo.gif" >
</div>
<div class="login_banner">
<div id="l_content">
<span class="login_word">欢迎注册</span>
</div>
<div id="content">
<div class="login_form">
<div class="login_box">
<div class="tit">
<h1>注册尚硅谷会员</h1>
<span class="errorMsg"></span>
</div>
<div class="form">
<form action="http://localhost:8080">
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username" id="username" />
<br />
<br />
<label>用户密码:</label>
<input class="itxt" type="password" placeholder="请输入密码"
autocomplete="off" tabindex="1" name="password" id="password" />
<br />
<br />
<label>确认密码:</label>
<input class="itxt" type="password" placeholder="确认密码"
autocomplete="off" tabindex="1" name="repwd" id="repwd" />
<br />
<br />
<label>电子邮件:</label>
<input class="itxt" type="text" placeholder="请输入邮箱地址"
autocomplete="off" tabindex="1" name="email" id="email" />
<br />
<br />
<label>验证码:</label>
<input class="itxt" type="text" style="width: 150px;" id="code"/>
<img alt="" src="../../static/img/code.bmp" style="float: right; margin-right: 40px">
<br />
<br />
<input type="submit" value="注册" id="sub_btn" />
</form>
</div>
</div>
</div>
</div>
</div>
<div id="bottom">
<span>
尚硅谷书城.Copyright ©2015
</span>
</div>
</body>
</html>
第二阶段:用户登录和注册
需求
需求1:用户注册
需求如下:1)访问注册页面
2)填写注册信息,提交给服务器
3)服务器应该保存用户
4)当用户已经存在----提示用户注册 失败,用户名已存在
5)当用户不存在-----注册成功
需求2:用户登陆
需求如下:
1)访问登陆页面
2)填写用户名密码后提交
3)服务器判断用户是否存在
Java EE项目的三层结构
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。
项目的包分类
web层 com.atguigu.web/servlet/controller
service层 com.atguigu.service Service接口包
com.atguigu.service.impl Service接口实现类
dao持久层 com.atguigu.dao Dao接口包
com.atguigu.dao.impl Dao接口实现类
实体bean对象 com.atguigu.pojo/entity/domain/bean JavaBean 类
测试包 com.atguigu.test/junit
工具类 com.atguigu.utils
IDEA搭建书城项目开发环境
创建动态java工程 file--new--module--勾选Web Application,在web中导入静态文件资源pages,static,index.html,在src下创建对应的包
创建书城的数据库和表
drop database if exists book;
create database book;
use book;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(20) not null unique,
`password` varchar(32) not null,
`email` varchar(200)
);
insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@atguigu.com');
select * from t_user;
POJO层
编写数据库表对应的JavaBean对象
public class User {
private Integer id;
private String username;
private String password;
private String email;
...
//使用ctrl+alt+S快速生成get/set,toString方法和构造器
}
编写工具类JdbcUtils
1导入需要的jar(数据库和连接池需要)
2.找到相关的jar包,先不绑定具体的module,更改libraries的名字
3. 把book_lib添加到book工程
4.添加到artifacts中
2.在src源码目录下编写jdbc.properties属性配置文件
username=root
password=root
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10
3.编写JdbcUtils工具类
DruidDataSourceFactory.createDataSource(properties);
public class JdbcUtils {
//创建数据库连接池
private static DruidDataSource dataSource;
static {
try {
Properties properties = new Properties();
// 读取jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中加载数据
properties.load(inputStream);
// 创建数据库连接池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取数据库连接池中的连接
* @return 如果返回 null,说明获取连接失败<br/>有值就是获取连接成功
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接,放回数据库连接池
* @param conn
*/
public static void close(Connection conn){
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.JdbcUtils测试
public class JdbcUtilsTest {
@Test
public void testJdbcUtils(){
for (int i = 0; i < 100; i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
}
}
DAO层
编写BaseDao
在dao包下,BaseDao是复用的,没有具体对象,使用抽象类型
public abstract class BaseDao {
//使用dbutils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* update()方法用来执行:Insert\Update\Delete语句
* @param sql
* @param args
* @return 如果返回-1,说明执行失败,返回其他表示影响的行数
*/
public int update(String sql,Object ... args) {
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.update(conn, sql, args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return -1;
}
/**
* 查询返回一个javaBean的sql
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数
* @param <T> 返回的类型的泛型
* @return
*/
public <T> T queryForOne(Class<T> type,String sql,Object... args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new BeanHandler<>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
/**
* 查询返回多个javaBean的sql
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> List<T> queryForList(Class<T> type,String sql,Object...args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new BeanListHandler<>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
/**
* 返回执行一行一列的sql
* @param sql 执行的sql语句
* @param args sql对应的参数值
** @return
*/
public Object queryForSingleValue(String sql,Object...args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new ScalarHandler(),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
}
编写UserDao和测试
方法都是和用户类需要用到的情境相关
public interface UserDao {
/**
* 根据用户名查询用户信息
* @param username 用户名
* @return 如果返回null,说明没有这个用户,反之亦然
*/
public User queryUserByUsername(String username);
/**
* 根据用户名和密码查询用户信息
* @param username
* @param password
* @return 返回null,说明用户名或密码错误,反之亦然
*/
public User queryUserByUsernameAndPassword(String username,String password);
/**
*保存用户信息
* @param user
* @return 返回-1表示操作失败,其他是sql语句影响的行数
*/
public int saveUser(User user);
}
UserDaoImlp实现类
实现UserDao的方法
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ?";
return queryForOne(User.class,sql,username);
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ? and password = ?";
return queryForOne(User.class,sql,username,password);
}
@Override
public int saveUser(User user) {
String sql ="insert into t_user (`username`,`password`,`email`) values(?,?,?)";
return update(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
}
UserDao测试类
自动生成测试类
public class UserDaoImplTest {
UserDao userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if(userDao.queryUserByUsername("admin")==null){
System.out.println("用户名可用");
}else{
System.out.println("用户名已存在");
}
}
@Test
public void queryUserByUsernameAndPassword() {
if ( userDao.queryUserByUsernameAndPassword("admin","admin1234") == null) {
System.out.println("用户名或密码错误,登录失败");
} else {
System.out.println("查询成功");}
}
@Test
public void saveUser() {
System.out.println( userDao.saveUser(new User(null,"wzg168", "123456", "wzg168@qq.com")) );
}
}
Service层
编写UserService和测试
service表示业务,一个业务一个方法.(业务包含登录/注册/检查用户是否可用)
UserService接口
public interface UserService {
/**
* 注册用户
* @param user
*/
public void registUser(User user);
/**
* 登录
* @param user
* @return 如果返回null,说明登录失败,返回有值说明登录成功
*/
public User login(User user);
/**
* 检查用户名是否可用
* @param username
* @return 返回true表示用户名已存在,返回false表示用户名可用
*/
public boolean existUsername(String username);
}
UserServiceImpl实现类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void registUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
}
@Override
public boolean existUsername(String username) {
if(userDao.queryUserByUsername(username)==null){
//等于null,没找到表示可用
return false;
}
return true;
}
}
UserService测试
public class UserServiceImplTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null,"bbj168","666666","bbj168@qq.com"));
userService.registUser(new User(null,"abc168","666666","abc168@qq.com"));
}
@Test
public void login() {
System.out.println(userService.login(new User(null, "asd", "123456", null)));
System.out.println(userService.login(new User(null, "abc168", "666666", "abc168@qq.com")));
}
@Test
public void existUsername() {
if(userService.existUsername("abc1608")){
System.out.println("用户名已存在");
}else{
System.out.println("用户名可用");
}
}
}
web层
修改regist.html和regist_success.html页面
<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8080/book/">
2、修改base标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
以下是几个修改的示例:
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script
3、修改注册表单的提交地址和请求方式
编写RegistServlet程序
public class RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
// 2、检查 验证码是否正确 === 写死,要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)) {
// 3、检查用户名是否可用
if (userService.existsUsername(username)) {
System.out.println("用户名[" + username + "]已存在!");
// 跳回注册页面
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
} else {
// 可用
// 调用Sservice 保存到数据库
userService.registUser(new User(null, username, password, email));
// 跳到注册成功页面 regist_success.html
req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp);
}
} else {
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
}
}
}
IDEA中Debug调试的使用
Debug调试代码,首先需要两个元素:断点+Debug启动服务器
1、断点,只需要在代码需要停的行的左边上单击,就可以添加和取消
2、Debug启动Tomcat运行代码:
测试工具栏:
变量窗口
它可以查看当前方法范围内所有有效的变量。
方法调用栈窗口
1、方法调用栈可以查看当前线程有哪些方法调用信息
2、下面的方法调用上一行的方法其他常用调试相关按钮:
其他常用调试相关按钮:
用户登录功能的实现
图解用户登录
修改 login.html 页面和 login_success.html 页面
<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8080/book/">
2、修改base标签对页面中所有相对路径的影响(浏览器F12,哪个报红,改哪个)
以下是几个修改的示例:
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//调用userService.login()登录处理业务
User loginUser = userService.login(new User(null, username, password, null));
// 如果等于 null,说明登录 失败!
if (loginUser == null) {
// 跳回登录页面
req.getRequestDispatcher("/pages/user/login.html").forward(req, resp);
} else {
//登录成功
//跳到成功页面login_success.html
req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp);
}
}
}
第三阶段:代码优化
页面jsp动态化
为了实现页面的反馈效果,将静态html改为jsp
1、在html面顶行添加page指令。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2、修改文件后缀名为:.jsp(右键--refactor--rename)
3、使用IDEA搜索替换.html 为.jsp(edit--find --replace in path),将文件中出现的html内容改为jsp
抽取页面中相同的内容
如上内容在多个页面中出现,我们将其抽取出为一个公共的JSP页面然后引用,减少代码维护量
login_success_menu.jsp
<div>
<span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
<a href="../order/order.jsp">我的订单</a>
<a href="../../index.jsp">注销</a>
<a href="../../index.jsp">返回</a>
</div>
order.jsp/login_success.jsp/cart.jsp/checkout.jsp
<%--静态包含登录成功之后的菜单--%>
<%@include file="/pages/common/login_success_menu.jsp"%>
<!--写base标签,永远固定相对路径跳转的结果-->
<base href="http://localhost:8080/book/">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
每个jsp文件中都改动
<%--静态包含base标签,css样式,iquery文件--%>
<%@include file="/pages/common/head.jsp"%>
每个页面的页脚
<div id="bottom">
<span>