书城项目
书城项目
第一阶段:表单验证
验证用户名:必须由字母,数字下划线组成,并且长度在5-12位
验证密码:必须由字母,数字下划线组成,并且长度为5-12位
验证确认密码:和密码相同
邮箱验证:xxxxx@xxx.com
验证码:现在只需要验证用户已输入,因为还没将到服务器,验证码生成。
1、新建一个模块
2、把书城的静态资源拷贝到模块工程下
<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(); //去掉验证码前后空格 codeText = $.trim(codeText); if(codeText==null ||codeText=="" ){ $("span.errorMsg").text("验证码不能为空!") return false; } $("span.errorMsg").text(""); }); });
第二阶段:用户注册和登录
1、JavaEE项目的三层架构
分层的目的是为了解耦,解耦就是为了降低代码的耦合度,方便项目后期的维护和升级。
web层 com.lxg.web/servlet/controller service层 com.lxg.service Service接口包 com.lxg.service.impl Service接口实现类 dao持久层 com.lxg.dao Dao接口包 com.lxg.dao.impl Dao接口实现类 实体bean对象 com.lxg.pojo/entity/domain/bean JavaBean类 测试包 com.lxg.test/junit 工具类 com.lxg.utils
2、编码环节
1、先创建书城需要的数据库和表
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@qq.com'); select * from t_user;
2、编写数据库表对应的JavaBean对象
package com.lxg.domain; public class User { private Integer id; private String username; private String password; private String email; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + '}'; } public User(Integer id, String username, String password, String email) { this.id = id; this.username = username; this.password = password; this.email = email; } public User() { } }
3、编写工具类JdbcUtils
package com.lxg.utils; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import java.io.InputStream; import java.sql.Connection; import java.util.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说明获取连接失败,反之成功 */ 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 (Exception e){ e.printStackTrace(); } } } }
测试
@Test public void testJdbcUtils(){ for (int i = 0; i < 100; i++) { Connection connection = JdbcUtils.getConnection(); System.out.println(connection); JdbcUtils.close(connection); } }
4、编写BaseDao
package com.lxg.dao; import com.lxg.utils.JdbcUtils; 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; 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 connection = JdbcUtils.getConnection(); try{ return queryRunner.update(connection,sql,args); }catch (Exception e){ e.printStackTrace(); }finally { JdbcUtils.close(connection); } 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 connection = JdbcUtils.getConnection(); try { return queryRunner.query(connection,sql,new BeanHandler<T>(type),args); } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.close(connection); } 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 connection = JdbcUtils.getConnection(); try { return queryRunner.query(connection,sql,new BeanListHandler<T>(type),args); } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.close(connection); } return null; } /** * 执行返回一行一列的sql语句 * @param sql 执行的sql语句 * @param args sql对应的参数值 * @return */ public Object queryForSingleValue(String sql,Object...args){ Connection connection = JdbcUtils.getConnection(); try { queryRunner.query(connection,sql,new ScalarHandler(),args); } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.close(connection); } return null; } }
5、编写UserDao和测试
package com.lxg.test; import com.lxg.dao.UserDao; import com.lxg.dao.impl.UserDaoImpl; import com.lxg.domain.User; import org.junit.Test; import static org.junit.Assert.*; public class UserDaoTest { 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","123456")==null){ System.out.println("用户名或密码错误"); }else{ System.out.println("登录成功"); } } @Test public void saveUser() { System.out.println(userDao.saveUser(new User(null,"lxg","123456","xiaolin@qq.com"))); } }
6、编写UserService和测试
package com.lxg.test; import com.lxg.domain.User; import com.lxg.service.UserService; import com.lxg.service.impl.UserServiceImpl; import org.junit.Test; import static org.junit.Assert.*; public class UserServiceTest { UserService userService = new UserServiceImpl(); @Test public void registUser() { userService.registUser(new User(null,"zs","123456","zs@qq.com")); userService.registUser(new User(null,"ls","123456","ls@qq.com")); } @Test public void login() { System.out.println(userService.login(new User(null,"zs","123456",null))); } @Test public void existsUsername() { if(userService.existsUsername("zs")){ System.out.println("用户名已存在"); }else { System.out.println("用户名可用"); } } }
7、编写web层
1、用户注册
需求如下: 1、访问注册页面 2、填写注册信息,提交给服务器 3、服务器应该保存用户 4、当用户已经存在——提示用户注册失败,用户名已存在 5、当用户不存在——注册成功
package com.lxg.web; import com.lxg.domain.User; import com.lxg.service.UserService; import com.lxg.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 { 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{ //用户名可用 //调用service保存到数据库 userService.registUser(new User(null,username,password,email)); //跳转到注册成功页面 req.getRequestDispatcher("/pages/user/regist_success.html").forward(req,resp); } }else{ System.out.println("验证码["+code+"]错误"); //跳回注册页面 req.getRequestDispatcher("/pages/user/regist.html").forward(req,resp); } } }
2、用户登录
需求如下: 1、访问登录页面 2、填写用户名和密码后提交 3、服务器判断用户是否存在 4、如果登录失败——返回用户名或密码的错误信息
package com.lxg.web; import com.lxg.domain.User; import com.lxg.service.UserService; import com.lxg.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 { 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"); //2、调用userService.login完成业务逻辑 User loginUser= userService.login(new User(null,username, password,null)); //如果等于null,说明登录失败 if(loginUser==null){ //3、跳转到登录页面 req.getRequestDispatcher("/pages/user/login.html").forward(req,resp); }else { //4、登录成功,跳转到登录成功页面 req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp); } } }
3、IDEA中的Debug调试的使用
Debug调试代码,首先需要两个元素:断点+Debug启动服务器 1、断点:只需要在代码需要停的行的左边上单击,就可以添加和取消 2、Debug服务器启动Tomcat运行代码:点击调试按钮
测试工具栏:
变量窗口,它可以查看当前方法范围内所有有效变量
方法调用窗口
1、方法调用栈可以查看当前线程有哪些方法调用信息 2、下面一行的方法调用上面一行的方法
其他常用调试相关按钮:
第三阶段:优化
a:页面jsp动态化
- 在html页面顶行添加page指令
- 修改文件后缀名为:.jsp
3.使用idea搜索替换.html为.jsp
CTRL+SHIF+R:或者CTRL+R
b:抽取页面相同的内容
c:登录,注册错误提示以及表单回显
在Servlet后端代码中将用户信息保存进域对象,
在jsp前端页面代码中使用EL表达式获取信息并显示
d:BaseServlet的抽取
在实际的项目开发中,一个模块,一般只使用一个Servlet程序。
LoginServlet和RegistServle优化为UserServlet:
package main.java.com.lxg.web; import main.java.com.lxg.domain.User; import main.java.com.lxg.service.UserService; import main.java.com.lxg.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 UserServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); /** * 处理登录功能 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //System.out.println("处理登录的需求"); // 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) { // 把错误信息,和回显的表单项信息,保存到Request域中 req.setAttribute("msg", "用户或密码错误!"); req.setAttribute("username", username); // 跳回登录页面 req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp); } else { // 登录 成功 //跳到成功页面login_success.html req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp); } } /** * 处理注册功能 * * @param req * @param resp * @throws ServletException * @throws IOException */ protected void regist(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 + "]已存在!"); // 把回显信息,保存到Request域中 req.setAttribute("msg", "用户名已存在!!"); req.setAttribute("username", username); req.setAttribute("email", email); //跳回注册页面 req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp); } else { //可用 //调用Sservice保存到数据库 userService.registUser(new User(null, username, password, email)); //跳到注册成功页面 regist_success.jsp req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp); } } else { // 把回显信息,保存到Request域中 req.setAttribute("msg", "验证码错误!!"); req.setAttribute("username", username); req.setAttribute("email", email); System.out.println("验证码[" + code + "]错误"); req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); if ("login".equals(action)) { login(req, resp); } else if ("regist".equals(action)) { regist(req, resp); } } }
doPost还可以继续优化为:
String action = req.getParameter("action"); try { //通过action业务鉴别字符串,获取对应的业务,方法反射对象 Method method = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class); //System.out.println(method); //调用目标业务方法 method.invoke(this,req,resp); } catch (Exception e) { e.printStackTrace(); }
如若系统又有其他模块,这个代码可以抽取出来变成BaseServlet
e:数据的封装和抽取BeanUtils的使用
-
BeanUtils工具类,它可以一次性的把请求的参数注入到javaBean中。
-
BeanUtils不是jdk的类,是第三方的工具类,所以需要导包
-
导入需要的jar包:
commons-beanutils-1.8.0.jar
commons-logging-1.1.1.jar -
使用BeanUti类方法实现注入
-
package main.java.com.lxg.utils; import org.apache.commons.beanutils.BeanUtils; import java.util.Map; public class WebUtils { /** * 把Map中的值注入到对应的JavaBean属性中。 * @param value * @param bean */ public static <T> T copyParamToBean(Map value, T bean){ try { System.out.println("注入之前:"+bean); /** * 把所有请求的参数全都注入到user对象中 */ BeanUtils.populate(bean,value); System.out.println("注入之后:"+bean); } catch (Exception e) { e.printStackTrace(); } return bean; } }
//给参数注入值 User user = WebUtils.copyParamToBean(req.getParameterMap(),new User());
CTRL+ALT+T快捷键:
第四阶段:使用EL表达式修改表单回显(上面已修改)
第五阶段:图书模块
1、MVC概念
MVC全称:Model模型、View视图、Controller控制器 MVC最早出现在JavaEE三层的web层,它可以有效的指导web层的代码如何有效分离,单独工作 View视图:只负责数据和界面的显示,不接受任何域显示数据无关的代码,便于程序员和美工的分工合作---jsp/Html Controller控制器:只负责接收请求,调用业务层的代码请求,然后派发页面,是一个“调度者”的角色--Servlet。转到某个页面,或者是重定向到某个页面。 Model模型:将与业务逻辑相关的数据封装成为具体的JavaBean类,其中不掺杂任何与数据处理相关的代码--JavaBean、domain、entity。 MVC是一种思想 MVC的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了解耦合)。
MVC的作用还是为了降低耦合,让代码合理分层,方便后期升级和维护。
2、图书模块
2.1、编写图书模块的数据库表
2.2、编写图书模块的JavaBean
package main.java.com.lxg.domain; import java.math.BigDecimal; public class Book { private Integer id; private String name; private String author; private BigDecimal price; private Integer sales; private Integer stock; private String imgPath="static/img/default.jpg"; public Book() { } @Override public String toString() { return "Book{" + "id=" + id + ", name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + ", sales=" + sales + ", stock=" + stock + ", imgPath='" + imgPath + '\'' + '}'; } 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 String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public BigDecimal getPrice() { return price; } public void setPrice(BigDecimal price) { this.price = price; } public Integer getSales() { return sales; } public void setSales(Integer sales) { this.sales = sales; } public Integer getStock() { return stock; } public void setStock(Integer stock) { this.stock = stock; } public String getImgPath() { return imgPath; } public void setImgPath(String imgPath) { //要求给定的图书封面图书路径不能为空 if (imgPath!=null && !"".equals(imgPath)){ this.imgPath = imgPath; } } public Book(Integer id, String name, String author, BigDecimal price, Integer sales, Integer stock, String imgPath) { this.id = id; this.name = name; this.author = author; this.price = price; this.sales = sales; this.stock = stock; //要求给定的图书封面图书路径不能为空 if (imgPath!=null && !"".equals(imgPath)){ this.imgPath = imgPath; } } }
2.3、编写图书模块的Dao和测试Dao
package main.java.com.lxg.dao; import main.java.com.lxg.domain.Book; import java.util.List; public interface BookDao { public int addBook(Book book); public int deleteBookById(Integer id); public int updateBook(Book book); public Book queryBookById(Integer id); public List<Book> queryBooks(); }
package main.java.com.lxg.dao.impl; import main.java.com.lxg.dao.BookDao; import main.java.com.lxg.domain.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`) \n" + "values(?,?,?,?,?,?)"; return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath()); } @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.getImgPath(),book.getId()); } @Override public Book queryBookById(Integer id) { String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imPath from t_book where id=? "; return queryForOne(Book.class,sql,id); } @Override public List<Book> queryBooks() { String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` from t_book"; return queryForList(Book.class,sql); } }
生成测试快捷键:CTRL+SHIFT+T
2.4、编写图书模块的Service和测试Service
package main.java.com.lxg.service; import main.java.com.lxg.domain.Book; import java.util.List; public interface BookService { public void addBook(Book book); public void deleteBookById(Integer id); public void updateBook(Book book); public Book findBookById(Integer id); public List<Book> findAllBooks(); }
package main.java.com.lxg.service.impl; import main.java.com.lxg.dao.BookDao; import main.java.com.lxg.dao.impl.BookDaoImpl; import main.java.com.lxg.domain.Book; import main.java.com.lxg.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 findBookById(Integer id) { return bookDao.queryBookById(id); } @Override public List<Book> findAllBooks() { return bookDao.queryBooks(); } }
2.5、编写图书模块的Web层,和页面联调测试
BookServlet:
package main.java.com.lxg.web; import main.java.com.lxg.domain.Book; import main.java.com.lxg.service.BookService; import main.java.com.lxg.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{ private BookService bookService = new BookServiceImpl(); protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、通过BookService查询全部图书 List<Book> books = bookService.findAllBooks(); //2、把全部图书信息保存到Req域中 req.setAttribute("books",books); //3、请求转发到pages/manager/book_manager.jsp页面 req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp); } }
需要给BaseServlet加上doGet方法才可处理get请求
@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp); }
实现展示所有图书功能:
使用jstl标签遍历获取数据显示在前端页面:
<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="#">删除</a></td> </tr> </c:forEach>
前后台的介绍:
实现添加图书功能:
请求转发定位到工程目录
请求重定向定位到端口号
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、获取请求的参数==封装成为Book对象 Book book = WebUtils.copyParamToBean(req.getParameterMap(),new Book()); //2、调用BookService.addBook()保存图书 bookService.addBook(book); //3、跳到图书列表页面 //req.getRequestDispatcher("/manager/bookServlet?action=list").forward(req,resp); resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list"); }
实现图书删除功能:
<script type="text/javascript"> $(function (){ //给删除的a标签绑定单击事件 $("a.deleteClass").click(function () { //在事件的function函数中,有一个this对象,这个this对象,是当前正在响应事件的dom对象 /** * confirm是确认提示框函数 * 参数是它提示的内容 * 它有两个按钮,一个确定,一个是取消 * 返回true表示点击了确定,返回false表示点击了取消 */ return confirm("你确定要删除【"+$(this).parent().parent().find("td:first").text()+"】?"); }) }); </script>
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、获取请求的参数id,图书编号 int id = WebUtils.parseInt(req.getParameter("id"),0); //2、调用BookService.deleteBookById(id); bookService.deleteBookById(id); //3、重定向会图书列表管理页面 resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list"); }
<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
实现图书修改功能:
获取前端页面数据:
protected void getBook(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、获取请求的参数,图书编号 int id = WebUtils.parseInt(req.getParameter("id"),0); //2、调用bookService.queryBookById查询图书 Book book = bookService.findBookById(id); //3、保存图书信息到request域中 req.setAttribute("book",book); //4、请求转发到,pages/maanger/book_edit.jsp页面 req.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(req,resp); }
回显数据:
<tr> <td><input name="name" type="text" value="${book.name}"/></td> <td><input name="price" type="text" value="${book.price}"/></td> <td><input name="author" type="text" value="${book.author}"/></td> <td><input name="sales" type="text" value="${book.sales}"/></td> <td><input name="stock" type="text" value="${book.stock}"/></td> <td><input type="submit" value="提交"/></td> </tr>
保存修改:
<%--<input type="hidden" name="action" value="${param.method}">--%> <%--<input type="hidden" name="action" value="${empty param.id ? "add" : "update"}">--%> <input type="hidden" name="action" value="${empty requestScope.book ? "add" : "update"}">
<%--<td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>--%> <td><a href="pages/manager/book_edit.jsp">添加图书</a></td>
<%--<td><a href="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>--%> <td><a href="manager/bookServlet?action=getBook&id=${book.id}">修改</a></td
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1、获取请求的参数==封装成Book对象 Book book = WebUtils.copyParamToBean(req.getParameterMap(),new Book()); //2、调用BookService.updateBook(book);修改图书 bookService.updateBook(book); //3、重定向会图书列表管理页面 resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list"); }
3、图书分页
-
分页功能分析
-
分页模型Page对象的创建
-
分页初步实现
-
首页,上一页,末页的实现
-
跳转到指定页码的功能
-
数据边界有效的检验
-
分页条页码的显示(显示5个连续的页码,而且当前页码在中间,除了当前页码之外,每个页码都可以点击跳转到相应的指定页面
-
修改分页对原来添加修改删除功能的影响
4、前台分页
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@page contentType="text/html;charset=UTF-8" language="java" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>书城首页</title> <%--静态包含base标签,css样式,jQuery文件--%> <%@ include file="/pages/common/head.jsp"%> </head> <body> <div id="header"> <img class="logo_img" alt="" src="static/img/logo.gif" > <span class="wel_word">网上书城</span> <div> <a href="pages/user/login.jsp">登录</a> | <a href="pages/user/regist.jsp">注册</a> <a href="pages/cart/cart.jsp">购物车</a> <a href="pages/manager/manager.jsp">后台管理</a> </div> </div> <div id="main"> <div id="book"> <div class="book_cond"> <form action="" method="get"> 价格:<input id="min" type="text" name="min" value=""> 元 - <input id="max" type="text" name="max" value=""> 元 <input type="submit" value="查询" /> </form> </div> <div style="text-align: center"> <span>您的购物车中有3件商品</span> <div> 您刚刚将<span style="color: red">时间简史</span>加入到了购物车中 </div> </div> <c:forEach items="${requestScope.page.items}" var="book" > <div class="b_list"> <div class="img_div"> <img class="book_img" alt="" src="${book.imgPath}" /> </div> <div class="book_info"> <div class="book_name"> <span class="sp1">书名:</span> <span class="sp2">${book.name}</span> </div> <div class="book_author"> <span class="sp1">作者:</span> <span class="sp2">${book.author}</span> </div> <div class="book_price"> <span class="sp1">价格:</span> <span class="sp2">¥${book.price}</span> </div> <div class="book_sales"> <span class="sp1">销量:</span> <span class="sp2">${book.sales}</span> </div> <div class="book_amount"> <span class="sp1">库存:</span> <span class="sp2">${book.stock}</span> </div> <div class="book_add"> <button>加入购物车</button> </div> </div> </div> </c:forEach> </div> <div id="page_nav"> <%--大于首页才显示--%> <c:if test="${requestScope.page.pageNo>1}"> <a href="client/bookServlet?action=page&pageNo=1">首页</a> <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo-1}">上一页</a> </c:if> <%--页码输出的开始--%> <c:choose> <%--1、总页码小于等于五,页码范围1-总页码--%> <c:when test="${requestScope.page.pageTotal<=5}"> <c:set var="begin" value="1"/> <c:set var="end" value="${requestScope.page.pageTotal}"/> </c:when> <%--2、总页码大于五--%> <c:when test="${requestScope.page.pageTotal>5}"> <c:choose> <%--2.1当前页码为前面三个,1,2,3的情况-,页码范围为1到5--%> <c:when test="${requestScope.page.pageNo <=3}"> <c:set var="begin" value="1"/> <c:set var="end" value="5"/> </c:when> <%--2.2当前页码为最后三个,页码范围为总页码减4到总页码--%> <c:when test="${requestScope.page.pageNo>requestScope.page.pageTotal-3}"> <c:set var="begin" value="${requestScope.page.pageTotal-4}"/> <c:set var="end" value="${requestScope.page.pageTotal}"/> </c:when> <%--2.3:剩下的页码--%> <c:otherwise> <c:set var="begin" value="${requestScope.page.pageNo-2}"/> <c:set var="end" value="${requestScope.page.pageNo+2}"/> </c:otherwise> </c:choose> </c:when> </c:choose> <c:forEach begin="${begin}" end="${end}" var="i"> <c:if test="${i==requestScope.page.pageNo}"> 【${i}】 </c:if> <c:if test="${i!=requestScope.page.pageNo}"> <a href="client/bookServlet?action=page&pageNo=${i}">${i}</a> </c:if> </c:forEach> <%--页码输出的结束--%> <%--如果已经是最后一页,则不显示下一页和末页--%> <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}"> <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo+1}">下一页</a> <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页</a> </c:if> 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录 到第<input value="${param.pageNo}" name="pn" id="pn_input"/>页 <input id="searchPageBtn" type="button" value="确定"> <script type="text/javascript"> $(function (){ //跳到指定的页码 $("#searchPageBtn").click(function (){ var pageNo = $("#pn_input").val(); //js语言提供了一个location地址栏对象 //它有一个属性叫href,它可以获取浏览器地址栏中的地址 location.href="${pageScope.basePath}client/bookServlet?action=page&pageNo="+pageNo; }); }); </script> </div> </div> <%--静态包含页脚内容--%> <%@include file="/pages/common/footer.jsp"%> </body> </html>
根据价格区间查询数据并分页:
第六阶段:登录登出
1、登录
a、显示用户名
2、登出
a、注销用户
1、销毁session中用户登录的信息(或者销毁session)
2、重定向到首页或者登录界面
3、表单重复提交
有三种常见情况:
1、提交完表单,服务器使用请求转发来进行页面跳转,这个时候用户按下F5功能键,就会发起最后一次的请求,造成表单重复提交问题。 解决方法是使用重定向来进行页面跳转 2、用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交 3、用户正常提交服务器,服务器也没有延迟,但是提交完成之后,用户回退浏览器,重新提交,也会造成表单重复提交 后两种因没有可直接解决的方法,后引入验证码,使用验证码防止用户恶意提交
a、验证码
验证码解决表单重复提交的底层原理
b、谷歌kaptcha图片验证码的使用
使用步骤如下:
1、导入谷歌验证码的jar包(kaptcha-2.3.2.jar) 2、在web.xml中去配置用于生成验证码的Servlet程序 <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> 3、在表单中使用img标签去显示验证码图片并使用它 验证码:<input type="text" style="width: 50px; " name="code"> <img src="http://localhost:8080/bookTest/kaptcha.jpg" style="width:110px;height: 20px; " alt=""><br/> 4、在服务器获取谷歌生成的验证码,和客户端发送过来的验证码比较使用
4、购物车模块
1、编写购物车模型
2、加入购物车功能的实现
3、购物车的展示
4、删除购物车商品项的功能
5、清空购物车
6、修改商品数量
7、加入购物车提醒功能
5、订单模块
1、创建数据库表
2、编写对应实体类
3、编写dao和测试dao
4、编写service和测试service
5、配置web.xml
6、编写OrderServlet
7、修改页面
第七阶段:权限检查
1、使用过滤器拦截
2、ThreadLocal的使用
它可以解决多线程的数据安全问题 ThreadLocal它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数据,集合) 特点: 1、ThreadLocal可以为当前线程关联一个数据(它可以是像Map一样存储数据,key为当前线程) 2、每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例 3、每个ThreadLocal对象实例定义的时候一般都是static类型 4、ThreadLocal中保存数据,在线程销毁后,会由JVM虚拟自动释放
3、使用Filter和ThreadLocal组合管理事务
1、使用ThreadLocal确保所有操作对象都使用同一个连接对象
2、使用Filter统一给所有Service方法都加上try—catch,来实现事物的管理
3、将所有异常都统一交给Tomcat,让Tomcat展示友好的错误信息页面
在web.xml配置错误页面跳转
第八阶段:AJAx
1、使用Ajax验证用户名是否可用
2、使用ajax修改加入购物车功能
第九阶段:
1、库存问题
2、其他模块
var msg = $(this).attr('orderMsg'); alert(msg);
本文作者:_xiaolin
本文链接:https://www.cnblogs.com/SilverStar/p/17415192.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)