文章目录
- 注册登录功能
- 编写了利用德鲁伊数据库连接池的jdbcutils工具类实现数据库连接和关闭
- 编写了dao层basedao,里面是一些用dbutils和自己写的jdbcutils实现的基本数据库查询和插入功能
- 建数据库user表,编写user类,编写userdao规范了用户的行为,查名字是否有注册过,保存注册的用户,根据登录查询用户是否在数据库。
- 编写userdao接口实现类userdaoimpl,继承basedao,因为要用到里面的方法。然后实现userdao接口。
- 编写service层,编写userservice接口规范操作,注册登录,注册的时候第一步验证是否重名。
- 编写userserviceimpl
- 编写registsevlet处理注册
- 编写loginservice实现登录
- 测试工具类
- 代码优化
- 图书模块
- 表单重复提交之验证码
- 购物车模块
- filter过滤器防止未登录用户进入后台页面
- 项目做崩了,sorry,我认输。在分页那里,我太难了。。。。。。。。。。。但是还是学到好多呜呜呜呜。。。。。跳图书管理页面是空白的,可能没得到request域的值,但是debug显示存进去了,控制台报错。
注册登录功能
package com.atguigu.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
try {
//读取配置文件
Properties properties =new Properties() ;
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("resource/druid.properties");
properties.load(inputStream);
dataSource= (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn=null;
try {
conn=dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn){
if (conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
package com.atguigu.dao.impl;
import com.atguigu.utils.JdbcUtils;
import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Objects;
public abstract class BaseDao {
//使用dbutils
private QueryRunner queryRunner = new QueryRunner();
public int update(String sql, Object... args) {
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return queryRunner.update(conn, sql, args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return -1;
}
public <T> T queryForOne(String sql, Class<T> type, Object... args) {
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return queryRunner.query(conn, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}
public <T> List<T> queryForList(String sql, Class<T> type, Object... args) {
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return queryRunner.query(conn, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}
public Object queryForSingleValue(String sql, Object... args) {
Connection conn = null;
try {
conn = JdbcUtils.getConnection();
return queryRunner.query(conn, sql, new ScalarHandler());
} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
}
return null;
}
}
package com.atguigu.dao;
import com.atguigu.pojo.User;
public interface UserDao {
public User queryUserByUsername(String username);
public User queryUserByUsernameAndPassword(String username,String password);
public int saveUser(User user);
}
package com.atguigu.dao.impl;
import com.atguigu.dao.UserDao;
import com.atguigu.pojo.User;
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(sql,User.class,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(sql,User.class,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());
}
}
package com.atguigu.service;
import com.atguigu.pojo.User;
public interface UserService {
public void registUser(User user);
public User login(User user);
public boolean existUsername(String username);
}
package com.atguigu.service.impl;
import com.atguigu.dao.UserDao;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
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){
return false;
}
return true;
}
}
package com.atguigu.web;
import com.atguigu.pojo.User;
import com.atguigu.service.UserService;
import com.atguigu.service.impl.UserServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class RegistServlet extends HttpServlet {
UserService userService=new UserServiceImpl();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单里的参数 input的name名字获取
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
if (code.equalsIgnoreCase("abcd")) {
if (userService.existUsername(username)){
System.out.println("name exist!!!");
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
else {
userService.registUser(new User(username,password,email));
//跳转注册成功页面
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}
} else {
//跳回注册页面
System.out.println("验证码["+code+"]错误");
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}
}
package com.atguigu.web;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import com.atguigu.service.impl.UserServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
UserServiceImpl userService = new UserServiceImpl();
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new User(username, password, null);
if (userService.login(user)!=null){
//页面跳转
request.getRequestDispatcher("pages/user/login_success.jsp").forward(request,response);
}else {
request.getRequestDispatcher("pages/user/regist.jsp").forward(request,response);
}
}
}
package com.atguigu.test;
import com.atguigu.dao.UserDao;
import com.atguigu.dao.impl.UserDaoImpl;
import com.atguigu.pojo.User;
import org.junit.Test;
import static org.junit.Assert.*;
public class UserDaoImplTest {
UserDao userDao=new UserDaoImpl();
@Test
public void queryUserByUsername() {
User user = new User();
user=userDao.queryUserByUsername("何艳莹");
System.out.println(user);
}
@Test
public void queryUserByUsernameAndPassword() {
System.out.println(userDao.queryUserByUsernameAndPassword("何艳莹","123"));
}
@Test
public void saveUser() {
System.out.println(userDao.saveUser(new User("何艳莹","123","he@163.com")));
}
}
代码优化
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
<span>
尚硅谷书城.Copyright ©2015
</span>
</div>
把下面代码到页面原有位置替换
<%@include file="/pages/common/foot.jsp"%>
如果别的ip访问会发现有些css样式还是localhost访问,会产生错误,是因为我们把base标签写死了
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--动态获取base标签值(工程路径)--%>
<%
String basePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
%>
<base href="<%=basePath%>">
<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规定的jsp页面写java代码的方式
将错误消息和回显的内容存在request域中
if (code.equalsIgnoreCase("abcd")) {
if (userService.existUsername(username)){
request.setAttribute("msg","用户名已存在");
request.setAttribute("username",username);
request.setAttribute("email",email);
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
else {
userService.registUser(new User(username,password,email));
//跳转注册成功页面
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}
} else {
//跳回注册页面
request.setAttribute("msg","验证码错误");
request.setAttribute("username",username);
request.setAttribute("email",email);
System.out.println("验证码["+code+"]错误");
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
msg是变量可以重名,会更新值。
<div class="login_form">
<div class="login_box">
<div class="tit">
<h1>注册尚硅谷会员</h1>
<span class="errorMsg">
<%=request.getAttribute("msg")==null?"":request.getAttribute("msg")%>
</span>
</div>
<div class="form">
<form action="registServlet" method="post">
<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"
value="<%=request.getAttribute("msg")==null?"":request.getAttribute("email")%>"
/>
<br />
<br />
<label>验证码:</label>
<input class="itxt" type="text" style="width: 150px;" id="code" name="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>
在登录和注册页面上设置一个隐藏域名字叫action,值为方法名字,比如登录页面值是登录和注册页面值为注册。通过获取action值判断应该执行什么操作。但是这样会使页面代码太杂乱,所以在userservlet页面将操作抽取为方法,通过反射调用方法,就避免了很多ifelse语句
上面是登录页面的隐藏域
package com.atguigu.web;
import com.atguigu.pojo.User;
import com.atguigu.service.impl.UserServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public class UserServlet extends HttpServlet {
UserServiceImpl userService = new UserServiceImpl();
protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = new User(username, password, null);
if (userService.login(user)!=null){
request.getRequestDispatcher("pages/user/login_success.jsp").forward(request,response);
}else {
//将错误信息放到request域中
request.setAttribute("Msg","用户名或密码错误");
request.setAttribute("username",username);
request.getRequestDispatcher("pages/user/login.jsp").forward(request,response);
}
}
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取表单里的参数 input的name名字获取
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
if (code.equalsIgnoreCase("abcd")) {
if (userService.existUsername(username)){
request.setAttribute("msg","用户名已存在");
request.setAttribute("username",username);
request.setAttribute("email",email);
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
else {
userService.registUser(new User(username,password,email));
//跳转注册成功页面
request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request,response);
}
} else {
//跳回注册页面
request.setAttribute("msg","验证码错误");
request.setAttribute("username",username);
request.setAttribute("email",email);
request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取jsp页面隐藏域action值
String action = request.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用目标业务方法
method.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
action值和调用方法同名,所以反射就可以用。
package com.atguigu.web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public abstract class BaseServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取jsp页面隐藏域action值
String action = request.getParameter("action");
try {
// 获取action业务鉴别字符串,获取相应的业务方法反射对象
Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
// 调用目标业务方法
method.invoke(this,request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
这样它继承了父类的dopost方法,进入父类dopost执行,之后反射执行子类方法。
可以把bean对象一次性注入进来,省去大量使用get和set方法但是表单的name属性必须和类的属性名字一样。
利用beanuntils工具类封装了一个webuntils工具类
package com.atguigu.web;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
public class WebUtils {
public static <T> T copyParamToBean(Map value, T bean){
try {
BeanUtils.populate(bean,value);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
可以省去上面那些get方法,直接将map键值对注入到user中。
全部修改
图书模块
package com.atguigu.dao.impl;
import com.atguigu.dao.BookDao;
import com.atguigu.pojo.Book;
import java.util.List;
public class BookDaoImpl extends BaseDao implements BookDao {
@Override
public int addBook(Book book) {
String sql="insert into t_book(`name` , `author` , `price` , `sales` , `stock` , `img_path`)values(?,?,?,?,?,?)";
return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImg_path());
}
@Override
public int deleteBookById(Integer id) {
String sql="delete from t_book where id=?";
return update(sql,id);
}
@Override
public int updateBook(Book book) {
String sql="update t_book set `name`=?,`author`=?,`price`=?,`sales`=?,`stock`=?,`img_path`=?where id=?";
return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImg_path(),book.getId());
}
@Override
public Book queryBookById(Integer id) {
String sql="select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` from t_book where id=? ";
return queryForOne(sql,Book.class,id);
}
@Override
public List<Book> queryBooks() {
String sql= "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` from t_book";
return queryForList(sql,Book.class);
}
}
package com.atguigu.service.impl;
import com.atguigu.dao.BookDao;
import com.atguigu.dao.impl.BookDaoImpl;
import com.atguigu.pojo.Book;
import com.atguigu.service.BookService;
import java.util.List;
public class BookServiceImpl implements BookService {
private BookDao bookDao= new BookDaoImpl();
@Override
public void addBook(Book book) {
bookDao.addBook(book);
}
@Override
public void deleteBookById(Integer id) {
bookDao.deleteBookById(id);
}
@Override
public void updateBook(Book book) {
bookDao.updateBook(book);
}
@Override
public Book queryBookById(Integer id) {
return bookDao.queryBookById(id);
}
@Override
public List<Book> queryBooks() {
return bookDao.queryBooks();
}
}
- 注意先编写list方法,先显示所有图书在页面才能添加删除图书,list方法需要获取数据库所有图书,但是jsp页面无法访问数据库,访问数据库的操作都在dao层,service层可以访问dao层,而servlet可以访问service层,所以我们点击manger.jsp上的图书馆管理不能直接跳book_manger,而是通过servlet的请求转发,因为请求转发共享一个request域,我们可以将数据库图书存到request域,然后在页面上遍历request域的图书。
common下的manger_menu修改路径
<div>
<%-- action 表示调用bookservlet的哪个方法--%>
<a href="manager/bookservlet?action=list">图书管理</a>
<a href="order_manager.jsp">订单管理</a>
<a href="../../index.jsp">返回商城</a>
</div>
注意action表示调用 bookservlet哪个方法名(和前面登录注册一样通过父类baseservlet的 dopost方法反射调用子类方法),携带上action参数转发
- 编写add方法
点击bookmanger上的添加跳转book_edit页面,所以去修改bookedit的表单action并添加隐藏域,修改下面input的book_name等和book类名字一样,否则beanuntils封装失败。
<div id="main">
<form action="manager/bookservlet" method="get">
<input type="hidden" name="action" value="add">
跳转的时候不能使用请求转发,因为请求转发是一次操作,刷新页面会再次执行,书会重复被存两边。所以用请求重定向合适。重定向注意路径。
- 删除方法
在页面删除地方设置action和id以及跳转路径
<c:forEach items="${requestScope.books}" var="book">
<tr>
<td>${book.name}</td>
<td>${book.price}</td>
<td>${book.author}</td>
<td>${book.sales}</td>
<td>${book.stock}</td>
<td><a href="book_edit.jsp">修改</a></td>
<td><a href="manager/bookservlet?action=delete&id=${book.id}">删除</a></td>
</tr>
</c:forEach>
给删除添加单击事件,弹窗确认
<script type="text/javascript">
// 给删除绑定单击事件
$(function () {
$("a.deleteClass").click(function () {
return confirm("你确定要删除【"+$(this).parent().parent().find("td:first").text()+"】?");
})
})
</script>
- 修改方法
思路是,点击删除跳转到book_edit.jsp页面,这个页面显示要修改的图书信息。这个页面如何获得图书的信息,还是要通过servlet,将bookmanager的图书信息传到request域,再转发到book_edit.jsp。然后修改,获取请求参数,封装成bean对象,调用bookservice.update更新数据,重定向回图书列表管理页面list。
有个问题是,添加和修改都要用到book_edit.jsp的隐藏域,那action怎么区别
- 通过让修改和添加携带method来区分
<input type="hidden" name="action" value="${param.method}">
- 通过是否携带参数有id
<input type="hidden" name="action" value="${empty param.id?"add":"update"}">
- 通过request域book对象是不是空,修改要回显,所以request域有book对象,添加没有。
<input type="hidden" name="action" value="${empty requestScope.book?"add":"update"}">
注意仅仅这样也不能修改,因为bookdaoimpl里update需要id。而bookedit提交给bookservlet的时候没有携带id的值,所以表单再增加一个隐藏域负责传参。
<input type="hidden" name="action" value="${empty requestScope.book?"add":"update"}">
<input type="hidden" name="id" value="${requestScope.book.id}">
点修改跳转回bookservlet时为了在bookedit回显,是携带着id的,所以request域中有id,用requestScope获取request域就能得到id。
最终bookservice如下
package com.atguigu.web;
import com.atguigu.pojo.Book;
import com.atguigu.service.impl.BookServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
public class BookServlet extends BaseServlet {
BookServiceImpl bookService = new BookServiceImpl();
protected void add(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
// 1,获取请求参数,封装成bean对象
Book book=WebUtils.copyParamToBean(request.getParameterMap(),new Book());
// 2,调用bookservice保存图书
bookService.addBook(book);
// 3,跳转到图书列表页面,book_manger.jsp
// request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request,response);
response.sendRedirect(request.getContextPath()+"/manager/bookservlet?action=list");
}
protected void delete(HttpServletRequest request,HttpServletResponse response) throws IOException {
int id =WebUtils.parseInt(request.getParameter("id"),0);
bookService.deleteBookById(id);
response.sendRedirect(request.getContextPath()+"/manager/bookservlet?action=list");
}
protected void update(HttpServletRequest request,HttpServletResponse response) throws IOException {
//1,获取请求参数,封装成bean对象\
Book book=WebUtils.copyParamToBean(request.getParameterMap(),new Book());
//2,调用bookservice.update更新数据
bookService.updateBook(book);
//3,重定向回图书列表管理页面list
response.sendRedirect(request.getContextPath()+"/manager/bookservlet?action=list");
}
//在bookedit回显修改的数据
protected void getBook(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
int id =WebUtils.parseInt(request.getParameter("id"),0);
Book book = bookService.queryBookById(id);
request.setAttribute("book",book);
request.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(request,response);
}
protected void list(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
// 1,通过bookservice调用dao层从数据库查询全部图书
List<Book> bookList = bookService.queryBooks();
// 2,将全部图书保存在request域中
request.setAttribute("books",bookList);
// 3,请求转发到book_manger.jsp
request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request,response);
}
}
思路,架构
session保存登录后用户信息,使韩总处显示登录后用户名,返回index页面时显示登录状态。
登录后返回首页显示用户信息,没有登录显示注册等。
<div id="header">
<img class="logo_img" alt="" src="static/img/logo.png" >
<span class="wel_word">网上书城</span>
<div>
<c:if test="${empty sessionScope.loginuser}">
<a href="pages/user/login.jsp">登录</a> |
<a href="pages/user/regist.jsp">注册</a>
</c:if>
<c:if test="${not empty sessionScope.loginuser}">
<span>欢迎<span class="um_span">${sessionScope.loginuser.username}</span>光临尚硅谷书城</span>
<a href="pages/order/order.jsp">我的订单</a>
<a href="userservlet?action=logout">注销</a>
</c:if>
<a href="pages/cart/cart.jsp">购物车</a>
<a href="pages/manager/manager.jsp">后台管理</a>
</div>
</div>
userservlet添加注销方法
// 注销
protected void logout(HttpServletRequest request,HttpServletResponse response) throws IOException {
// 销毁session
request.getSession().invalidate();
// 重定向
response.sendRedirect(request.getContextPath());
}
表单重复提交之验证码
- 验证码第三方提供了jar包,谷歌kaptcha,在web.xml中配置生成验证码的servlet类,jar包自带。会生成验证码并存在session中。
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
- 去表单img标签显示。
<br />
<label>验证码:</label>
<input class="itxt" type="text" style="width: 90px;" id="code" name="code"/>
<img alt="" src="kaptcha.jpg" style="float: right; margin-right: 40px"; width="110px"; height="40px">
<br />
- 在服务器获取谷歌生成的验证码和客户端发送的验证码比较。
protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取session中验证码
String token = (String) request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
//删除session
request.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
//获取表单里的参数 input的name名字获取
String username = request.getParameter("username");
String password = request.getParameter("password");
String email = request.getParameter("email");
String code = request.getParameter("code");
User user= WebUtils.copyParamToBean(request.getParameterMap(),new User());
if (token!=null&&token.equalsIgnoreCase(code)) {
if (userService.existUsername(username)){
request.setAttribute("msg","用户名已存在");
- 再实现看不清验证码刷新
给验证码图片绑定单击事件
<script>
$(function () {
$("#code_img").click(function () {
//修改当前dom对象的路径就会刷新,防止浏览器缓存加上时间
this.src="${basePath}/bookstore/kaptcha.jpg?d="+new Date();
})
});
</script>
购物车模块
因为这次用session存放购物车,所以没用到数据库dao层,所以方法没写在service层,而是写在了类方法里。
package com.atguigu.pojo;
import java.math.BigDecimal;
/**
* 购物车的商品项
*/
public class CartItem {
private Integer id;
private String name;
private Integer count;
private BigDecimal price;
private BigDecimal totalPrice;
public CartItem() {
}
public CartItem(Integer id, String name, Integer count, BigDecimal price, BigDecimal totalPrice) {
this.id = id;
this.name = name;
this.count = count;
this.price = price;
this.totalPrice = totalPrice;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public String toString() {
return "CartItem{" +
"id=" + id +
", name='" + name + '\'' +
", count=" + count +
", price=" + price +
", totalPrice=" + totalPrice +
'}';
}
}
package com.atguigu.pojo;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 购物车对象
*/
public class Cart {
// private Integer totalCount;
// private BigDecimal totalPrice;
/**
* key是商品编号,
* value,是商品信息
*/
private Map<Integer,CartItem> items = new LinkedHashMap<Integer,CartItem>();
/**
* 添加商品项
*
* @param cartItem
*/
public void addItem(CartItem cartItem) {
// 先查看购物车中是否已经添加过此商品,如果已添加,则数量累加,总金额更新,如果没有添加过,直接放到集合中即可
CartItem item = items.get(cartItem.getId());
if (item == null) {
// 之前没添加过此商品
items.put(cartItem.getId(), cartItem);
} else {
// 已经 添加过的情况
item.setCount( item.getCount() + 1 ); // 数量 累加
item.setTotalPrice( item.getPrice().multiply(new BigDecimal( item.getCount() )) ); // 更新总金额
}
}
/**
* 删除商品项
*/
public void deleteItem(Integer id) {
items.remove(id);
}
/**
* 清空购物车
*/
public void clear() {
items.clear();
}
/**
* 修改商品数量
*/
public void updateCount(Integer id,Integer count) {
// 先查看购物车中是否有此商品。如果有,修改商品数量,更新总金额
CartItem cartItem = items.get(id);
if (cartItem != null) {
cartItem.setCount(count);// 修改商品数量
cartItem.setTotalPrice( cartItem.getPrice().multiply(new BigDecimal( cartItem.getCount() )) ); // 更新总金额
}
}
public Integer getTotalCount() {
Integer totalCount = 0;
// Map的entrySet()方法返回一个实现Map.Entry接口的对象集合
for (Map.Entry<Integer,CartItem> entry : items.entrySet()) {
totalCount += entry.getValue().getCount();
}
return totalCount;
}
public BigDecimal getTotalPrice() {
BigDecimal totalPrice = new BigDecimal(0);
for (Map.Entry<Integer,CartItem>entry : items.entrySet()) {
totalPrice = totalPrice.add(entry.getValue().getTotalPrice());
}
return totalPrice;
}
public Map<Integer, CartItem> getItems() {
return items;
}
public void setItems(Map<Integer, CartItem> items) {
this.items = items;
}
@Override
public String toString() {
return "Cart{" +
"totalCount=" + getTotalCount() +
", totalPrice=" + getTotalPrice() +
", items=" + items +
'}';
}
}
这个购物车有点小难难,用map集合来存放购物车里商品。总数量总价直接在get里计算。
filter过滤器防止未登录用户进入后台页面
新建一个filter包,建一个ManagerFilter类
package com.atguigu.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
public class ManagerFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest=(HttpServletRequest)servletRequest;
Object user = httpServletRequest.getSession().getAttribute("loginuser");
if (user==null){
httpServletRequest.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletResponse);
}else {
filterChain.doFilter(servletRequest,servletResponse);
}
}
@Override
public void destroy() {
}
}
web.xml配置
<filter>
<filter-name>ManagerFilter</filter-name>
<filter-class>com.atguigu.filter.ManagerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ManagerFilter</filter-name>
<url-pattern>/pages/manager/*</url-pattern>
<url-pattern>/manager/bookservlet</url-pattern>
</filter-mapping>
防止进入后台servlet所以设置了两个拦截路径。
项目做崩了,sorry,我认输。在分页那里,我太难了。。。。。。。。。。。但是还是学到好多呜呜呜呜。。。。。跳图书管理页面是空白的,可能没得到request域的值,但是debug显示存进去了,控制台报错。
java.lang.NumberFormatException: null
at java.lang.Integer.parseInt(Integer.java:542)
at java.lang.Integer.parseInt(Integer.java:615)
at com.atguigu.web.WebUtils.parseInt(WebUtils.java:20)
at com.atguigu.web.BookServlet.page(BookServlet.java:57)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.atguigu.web.BaseServlet.doPost(BaseServlet.java:18)
at com.atguigu.web.BaseServlet.doGet(BaseServlet.java:24)