关于图片失效的问题,后面题主尽量重新填坑,因为我也忘了那些地方都是些什么图
第一阶段:表单验证
1、新建一个模块
2、把书城的静态资源拷贝到bookStore工程下
3、登录注册页面表单验证
在用户登录注册页面对输入数据进行一些规则限制
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>尚硅谷会员注册页面</title>
<link href="../../static/css/style.css" type="text/css" rel="stylesheet">
<script type="text/javascript" src="../../static/script/jquery-1.7.2.js"></script>
<script type="text/javascript">
$(function () {
$("#sub_btn").click(function () {
var username = $("#username").val();
var patt = /^[0-9a-zA-Z_-]{5,12}$/;
if(!patt.test(username)){
$("span.errorMsg").text("用户名不合法!");
return false;
}
var passtext = $("#password").val();
var patt = /^\w{5,12}$/;
if(!patt.test(passtext)){
$("span.errorMsg").text("请重新输入密码!");
return false;
}
var pwd = $("#repwd").val();
if(passtext != pwd){
$("span.errorMsg").text("两次密码输入不一致!");
return false;
}
var emitext = $("#email").val();
var emailpatt = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
if(!emailpatt.test(emitext)){
$("span.errorMsg").text("您的邮箱格式有误!");
return false;
}
var codetext = $("#code").val();
codetext = $.trim(codetext);
if(codetext == null || codetext == ""){
$("span.errorMsg").text("请输入验证码!");
return false;
}
$("span.errorMsg").text();
return false;
});
});
</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="userServlet" method="post">
<input type="hidden" name="action" value="regist">
<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" name="code" 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>
</body>
</html>
第二阶段:用户登录注册
1、JavaEE三层架构
- Web层/视图展现层
- 获取请求参数,封装成Bean对象
- 调用Service业务层处理业务
- 响应数据给客户端请求转发、重定向
- Servlet程序,Webwork,Strtus1.x,Strtus2.x,SpringMVC
- Service业务层
- 处理业务逻辑
- 调用持久层保存到数据库
- Spring框架
- Dao持久层
- Dao持久层,只负责跟数据库交互
- 执行CRUD操作
- Create 添加
- Read 读/查
- Update 修改
- Delete 删除
- JDBC,DbUtils,JdbcTemplate,Mybatis,Hiberante,JPA
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tTETvfQX-1647832234568)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_1638522597892.png)]
分层的目的是为了降低代码耦合度,方便日后项目的维护和升级
搭建书城项目开发环境:
web层 com.company.web/servlet/controller
service层 com.company.service Service接口包
? com.company.service.impl Service接口实现类
dao层 com.company.dao Dao接口包
? com.company.dao.impl Dao接口实现类
实体类对象 com.company.bean/pojo/entity/domain JavaBean类
测试包 com.company.test/junit
工具类 com.company.utils
2、创建书城需要的数据库和表
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@company');
3、编写数据库对应的JavaBean对象
package com.yitong.bean;
public class User {
private int id;
private String username;
private String password;
private String email;
public User() {
}
public User(int id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
public int getId() {
return id;
}
public void setId(int 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 + '\'' +
'}';
}
}
4、编写工具类JdbcUtils
package com.yitong.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("jdbc.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();
}
}
}
}
5、编写Base Dao类
package com.yitong.dao;
import com.yitong.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 {
private QueryRunner queryRunner = new QueryRunner();
public int update(String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try {
int update = queryRunner.update(connection, sql, args);
return update;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return -1;
}
public <T> T queryForOne(Class<T> type,String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try {
T query = queryRunner.query(connection, sql, new BeanHandler<T>(type), args);
return query;
} catch (SQLException e) {
e.printStackTrace();
}finally{
JdbcUtils.close(connection);
}
return null;
}
public <T> List<T> queryForList(Class<T> type,String sql,Object ... args){
Connection connection = JdbcUtils.getConnection();
try {
List<T> query = queryRunner.query(connection, sql, new BeanListHandler<T>(type), args);
return query;
} catch (SQLException e) {
e.printStackTrace();
}finally{
JdbcUtils.close(connection);
}
return null;
}
public Object queryForSingleValue(String sql,Object ... arg){
Connection connection = JdbcUtils.getConnection();
try {
Object query = queryRunner.query(connection, sql, new ScalarHandler(), arg);
return query;
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
}
6、编写UserDao接口类、实现类和测试类
UserDao的接口类
package com.yitong.dao;
import com.yitong.bean.User;
public interface UserDao {
public User queryUserByUsername(String username);
public User queryUserByUsernameAndPassword(String username,String password);
public int saveUser(User user);
}
UserDao实现类
package com.yitong.dao.impl;
import com.yitong.bean.User;
import com.yitong.dao.BaseDao;
import com.yitong.dao.UserDao;
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select * from t_user where username = ?";
User user = queryForOne(User.class, sql, username);
return user;
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select * from t_user where username = ? and password = ?";
User user = queryForOne(User.class, sql, username,password);
return user;
}
@Override
public int saveUser(User user) {
String sql = "insert into t_user (`username`,`password`,`email`) values (?,?,?)";
int update = update(sql, user.getUsername(), user.getPassword(), user.getEmail());
return update;
}
}
UserDao的测试类
package com.yitong.test;
import com.yitong.bean.User;
import com.yitong.dao.UserDao;
import com.yitong.dao.impl.UserDaoImpl;
import org.junit.Test;
public class UserDaoTest {
UserDao userDao = new UserDaoImpl();
@Test
public void UserDaoTest(){
String username = "admin";
User user1 = userDao.queryUserByUsername(username);
if (user1 == null) {
System.out.println("该用户不存在!");
}else{
System.out.println(user1);
}
String name = "root";
String password = "root";
User user2 = userDao.queryUserByUsernameAndPassword(name,password);
if (user2 == null) {
System.out.println("该用户不存在");
}else{
System.out.println(user2);
}
User user = new User("zhangsan","123456","root@qq.com");
int i = userDao.saveUser(user);
System.out.println(i);
}
}
7、编写UserService接口类实现类和测试类
UserService接口类
package com.yitong.service;
import com.yitong.bean.User;
public interface UserService {
public void registerUser(User user);
public User login(User user);
public boolean existUsername(String username);
}
UserServiceImpl接口实现类
package com.yitong.service.impl;
import com.yitong.bean.User;
import com.yitong.dao.UserDao;
import com.yitong.dao.impl.UserDaoImpl;
import com.yitong.service.UserService;
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void registerUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
}
@Override
public boolean existUsername(String username) {
User user = userDao.queryUserByUsername(username);
if(user == null){
return false;
}
return true;
}
}
service层测试类
package com.yitong.test;
import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.service.impl.UserServiceImpl;
import org.junit.Test;
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registerUser(){
userService.registerUser(new User("zhouqi","lisi","lisi@qq.com"));
}
@Test
public void login( ) {
userService.login(new User("root","root",null));
}
@Test
public void existUsername(){
userService.existUsername("lisi");
}
}
8、实现用户的注册功能
项目第二阶段:用户注册和登录的实现。
需求1:用户注册:当用户输入完成,就会点击提交,把参数都发送给服务器,去注册保存。
- 获取请求参数
- 检查验证码是否正确
? 功能需求:
? 访问注册页面
? 填写注册信息,提交给服务器
? 服务器应该保存用户注册失败,用户名已存在
? 当用户不存在,注册成功
RegisteServlet
package com.yitong.controller;
import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.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 {
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
if("abcde".equalsIgnoreCase(code)){
if(userService.existUsername(username)){
System.out.println("用户名:" + username + "不可用");
req.getRequestDispatcher("/pages/user/regist.html").forward(req,resp);
}else{
userService.registerUser(new User(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);
}
}
}
9、IDEA中Debug调试的使用
9.1、Debug调试
Debug调试代码,首先两个元素:断电+Debug启动服务器
- 断点,是需要在代码需要停止的行的左边上单击,就可以添加或取消。
- Debug启动Tomcat运行代码
9.2、调试工具栏
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nob5fzUv-1647832234569)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208144948405.png)]
? 1 2 4 3 5 6
- 表示让代码往下执行一行
- 可以进入当前方法体内(自己写的代码,非框架源码)
- 跳出当前方法体外
- 强制进入当前方法体内
- 停在光标所在行(相当于临时断点)
9.3、变量窗口
变量窗口:可以查看当前方法范围内所有有效的变量。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z693AQTS-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208152312767.png)]
9.4、方法调用栈窗口
- 方法调用栈可以查看当前线程有哪些方法调用信息。
- 下一行调用上一行的方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjsWCDTt-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208152334749.png)]
9.5、其他常用调试按钮:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cswfj7xI-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208151537440.png)]
第七个按钮:程序一直跑,直到下一个断点停下来。如果没有断点,就一直往下走
最后一个按钮:临时禁用所有断点
10、实现用户的登录功能
需求2:用户登录
- 获取请求参数
- 调用Xxx.Service.xxx()处理业务。
- 根据login()方法返回结果判断登录方式是否成功
? 功能需求:
? 访问登陆页面
? 填写用户名密码后提交
? 服务器判断用户是否存在
? 如果登录失败返回用户名或者密码错误信息
package com.yitong.controller;
import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.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 {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
User login = userService.login(new User(username, password, null));
if (login == null){
req.getRequestDispatcher("/pages/user/login.html").forward(req,resp);
}else {
req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
}
}
}
第三阶段:优化
1、页面jsp动态化
- 在HTML页面顶行添加page指令
- 修改文件后缀名为:.jsp
- 使用IDEA搜索替换.html后缀为.jsp(快捷键为:Ctrl + Shift + R)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fx4nr37G-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394518187103.png)]
2、抽取页面中相同的内容
2.1、head中的css、jquery、base标签
head.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--动态获取路径信息--%>
<%
String basePath = request.getScheme()
+ "://"
+ request.getServerName()
+ ":"
+ request.getServerPort()
+ request.getContextPath()
+ "/";
%>
<!--写base标签,永远固定相对路径跳转的结果:工程路径-->
<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>
页面中静态包含
<%--静态包含base标签,css样式,jQuery文件--%>
<%@include file="/pages/common/head.jsp"%>
2.2、每个页面的页脚
footer.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
<span>尚硅谷书城.Copyright ©2015</span>
</div>
页面静态包含
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
2.3、登录成功后的菜单
login_success_menu.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<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>
页面静态包含
<%--静态包含base标签,css样式,jQuery文件--%>
<%@include file="/pages/common/head.jsp"%>
2.4、manager模块的菜单
manager_menu.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<a href="book_manager.jsp">图书管理</a>
<a href="order_manager.jsp">订单管理</a>
<a href="../../index.jsp">返回商城</a>
</div>
页面静态包含
<%--静态包含manager管理模块的菜单--%>
<%@include file="/pages/common/manager_menu.jsp"%>
3、登录,注册错误提示,及表单回显
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cMj5S0zh-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394628072267.png)]
Servlet程序端添加回显信息显示到request域中,以注册为例
注册servlet
if("abcde".equalsIgnoreCase(code)){
if(userService.existUsername(username)){
req.setAttribute("msg","用户名已存在!");
req.setAttribute("username",username);
req.setAttribute("email",email);
System.out.println("用户名:" + username + "不可用");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}else{
userService.registerUser(new User(username,password,email));
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
}
}else{
req.setAttribute("msg","验证码错误!");
req.setAttribute("username",username);
req.setAttribute("email",email);
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}
注册信息页面
<%@ 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"%>
<script type="text/javascript">
$(function () {
$("#sub_btn").click(function () {
var usernameText = $("#username").val();
var usernamePatt = /^\w{5,12}$/;
if (!usernamePatt.test(usernameText)) {
$("span.errorMsg").text("用户名不合法!");
return false;
}
var passwordText = $("#password").val();
var passwordPatt = /^\w{5,12}$/;
if (!passwordPatt.test(passwordText)) {
$("span.errorMsg").text("密码不合法!");
return false;
}
var repwdText = $("#repwd").val();
if (repwdText != passwordText) {
$("span.errorMsg").text("确认密码和密码不一致!");
return false;
}
var emailText = $("#email").val();
var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
if (!emailPatt.test(emailText)) {
$("span.errorMsg").text("邮箱格式不合法!");
return false;
}
var codeText = $("#code").val();
codeText = $.trim(codeText);
if (codeText == null || codeText == "") {
$("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">
<%=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="请输入用户名"
value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"
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="请输入邮箱地址"
value="<%=request.getAttribute("email")==null?"":request.getAttribute("email")%>"
autocomplete="off" tabindex="1" name="email" id="email" />
<br />
<br />
<label>验证码:</label>
<input class="itxt" type="text" name="code" style="width: 150px;" id="code" value="abcde"/>
<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>
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
4、优化代码
4.1、合并LoginServlet和RegistServlet程序为UserServlet
在实际的项目开发中,一个模块只使用一个servlet程序
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBnrZkKE-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394656534980.png)]
package com.yitong.controller;
import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.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();
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
if("abcde".equalsIgnoreCase(code)){
if(userService.existUsername(username)){
req.setAttribute("msg","用户名已存在!");
req.setAttribute("username",username);
req.setAttribute("email",email);
System.out.println("用户名:" + username + "不可用");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}else{
userService.registerUser(new User(username,password,email));
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
}
}else{
req.setAttribute("msg","验证码错误!");
req.setAttribute("username",username);
req.setAttribute("email",email);
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
}
}
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
User login = userService.login(new User(username, password, null));
if (login == null){
req.setAttribute("msg","用户名或密码错误!");
req.setAttribute("username",username);
req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
}else {
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
if ("regist".equals(action)){
regist(req,resp);
}else if ("login".equals(action)){
login(req,resp);
}
}
}
给login.jsp和regist.jsp页面添加隐藏域和修改请求地址
<form action="userServlet" method="post">
<input type="hidden" name="action" value="login"/>
<form action="userServlet" method="post">
<input type="hidden" name="action" value="regist"/>
4.2、使用反射优化大量else if代码
实际项目中一个模块可能会有很对功能,每一个功能都在doPost中用else if判断再执行相应的方法回造成else if代码大量冗余。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6a96hEw-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394665424892.png)]
因此我们通过使用反射获取要执行的对应的方法对其进行执行。不用再大量的写else if语句判断。
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
try {
Method declaredMethod = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
declaredMethod.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
4.3、抽取BaseServlet程序
由于所有的Servlet都需要进行相同的反射操作调用相应的方法执行,所以将doPost抽取出来写成BaseServlet类,需要实现反射调用的类继承BaseServlet就可以完成代码的精简。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chrsy2fZ-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394694498391.png)]
package com.yitong.controller;
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 {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
try {
Method declaredMethod = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
declaredMethod.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
从此只需要继承BaseServlet而无需继承HttpServlet;
5、数据的封装和抽取BeanUtils的使用
BeanUtils工具类,它可以一次性的把所有请求的参数注入到JavaBean中。
BeanUtils工具类,经常用于把Map中的值注入到JavaBean中,或者是对象属性值的拷贝操作。
BeanUtils它不是JDK的类,而是一种第三方工具类。所以需要导包。
-
导入需要的jar包 commons-beanutils-1.8.0.jar commons-logging-1.1.1.jar -
使用BeanUtils类方法实现注入 ? 通过属性名和参数名对应的关系实现注入的,属性名是实体类中的定义的属性。参数名是表单中对应的name值。但注入找的是set方法,一旦set方法中的属性名和参数名不对应,尽管属性名和参数名相同,还是会注入失败。 BeanUtils.populate(bean,request.getParameterMap());
-
编写WebUtil工具类使用
package com.yitong.utils;
import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class WebUtils {
public static void copyParamToBean(HttpServletRequest req, Object bean){
try {
System.out.println("注入之前" + bean);
BeanUtils.populate(bean,req.getParameterMap());
System.out.println("注入之后" + bean);
} catch (Exception e) {
e.printStackTrace();
}
}
}
调用
WebUtils.copyParamToBean(request,user);
? 我们将Map的值注入到JavaBean中是很常见的。
java代码分为三层,dao层,Service层,servlet层。如果将参数写为HttpServletRequest req,Dao层和Service层没有这个API,不能使用这个方法,带来了Servlet层API的耦合度高。但是写成Map在三层都能使用这个方法
package com.yitong.utils;
import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class WebUtils {
public static void copyParamToBean(Map value, Object bean){
try {
System.out.println("注入之前" + bean);
BeanUtils.populate(bean,value);
System.out.println("注入之后" + bean);
} catch (Exception e) {
e.printStackTrace();
}
}
}
调用时
WebUtils.copyParamToBean(req.getParameterMap(),user);
优化
package com.yitong.utils;
import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class WebUtils {
public static Object copyParamToBean(Map value, Object bean){
try {
System.out.println("注入之前" + bean);
BeanUtils.populate(bean,value);
System.out.println("注入之后" + bean);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
User user = (User) WebUtils.copyParamToBean(req.getParameterMap(), new User());
再优化
package com.yitong.utils;
import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
public class WebUtils {
public static <T> T copyParamToBean(Map value, T bean){
try {
System.out.println("注入之前" + bean);
BeanUtils.populate(bean,value);
System.out.println("注入之后" + bean);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
User user = WebUtils.copyParamToBean(req.getParameterMap(), new User());
第四阶段:使用EL表达式修改表单回显
login.jsp
EL表达式null就是空串,所以空串可以不用判断,我们将表达式改为EL表达式
<span class="errorMsg">
<%--<%=request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg")%>--%>
${empty requestScope.msg ? "请输入用户名和密码":requestScope.msg}
</span>
<input class="itxt" type="text" placeholder="请输入用户名"
autocomplete="off" tabindex="1" name="username"
<%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
value="${requestScope.username}"/>
regist.jsp
<span class="errorMsg">
<%--<%=request.getAttribute("msg")==null?"":request.getAttribute("msg")%>--%>
${requestScope.msg}
</span>
<input class="itxt" type="text" placeholder="请输入用户名"
<%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
value="${ requestScope.username}"
autocomplete="off" tabindex="1" name="username" id="username" />
<input class="itxt" type="text" placeholder="请输入邮箱地址"
<%--value="<%=request.getAttribute("email")==null?"":request.getAttribute("email")%>"--%>
value="${requestScope.email}"
autocomplete="off" tabindex="1" name="email" id="email" />
第五阶段:图书模块
1、MVC概念
- MVC全称:Model模型、View视图、Controller控制器
- MVC最早出现再JavaEE三层中的web层,它可以有效的指导Web层的代码如何有效分离,单独工作。
- View视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML
- Controller控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。
- Model:将与业务逻辑相关的数据封装为具体JavaBean类,其中不掺杂任何与数据处理相关的代码——JavaBean/domain/entity/pojo
MVC是一种思想
MVC的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)。
让各层的代码尽可能的独立工作,而不产生依赖,方便后期升级和维护。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EihtKy8K-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16395317789938.png)]
2、图书模块
2.1、编写图书模块的数据库表
create table t_book(
`id` int primary key auto_increment,
`name` varchar(100),
`price` decimal(11,2),
`author` varchar(100),
`sales` int,
`stock` int,
`img_path` varchar(200)
);
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'java 从入门到放弃' , '国哥' , 80 , 9999 , 9 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '数据结构与算法' , '严敏君' , 78.5 , 6 , 13 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '怎样拐跑别人的媳妇' , '龙伍' , 68, 99999 , 52 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '木虚肉盖饭' , '小胖' , 16, 1000 , 50 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'C++编程思想' , '刚哥' , 45.5 , 14 , 95 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '蛋炒饭' , '周星星' , 9.9, 12 , 53 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '赌神' , '龙伍' , 66.5, 125 , 535 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'Java 编程思想' , '阳哥' , 99.5 , 47 , 36 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'JavaScript 从入门到精通' , '婷姐' , 9.9 , 85 , 95 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'cocos2d-x 游戏编程入门' , '国哥' , 49, 52 , 62 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'C 语言程序设计' , '谭浩强' , 28 , 52 , 74 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'Lua 语言程序设计' , '雷丰阳' , 51.5 , 48 , 82 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '西游记' , '罗贯中' , 12, 19 , 9999 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '水浒传' , '华仔' , 33.05 , 22 , 88 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '操作系统原理' , '刘优' , 133.05 , 122 , 188 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '数据结构 java 版' , '封大神' , 173.15 , 21 , 81 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'UNIX 高级环境编程' , '乐天' , 99.15 , 210 , 810 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'javaScript 高级编程' , '国哥' , 69.15 , 210 , 810 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '大话设计模式' , '国哥' , 89.15 , 20 , 10 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '人月神话' , '刚哥' , 88.15 , 20 , 80 , 'static/img/default.jpg');
select id,name,author,price,sales,stock,img_path from t_book;
2.2、编写图书模块的JavaBean
package com.yitong.bean;
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() {
}
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;
}
}
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;
}
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", sales=" + sales +
", stock=" + stock +
", imgPath='" + imgPath + '\'' +
'}';
}
}
2.3、编写图书模块的Dao和测试Dao
BookDao接口
package com.yitong.dao;
import com.yitong.bean.Book;
import java.util.List;
public interface BookDao {
public int addBook(Book book);
public int deleteBookById(int id);
public int updateBook(Book book);
public Book queryBookById(int id);
public List<Book> queryBooks();
}
BookDaoImpl接口实现类
package com.yitong.dao.impl;
import com.yitong.bean.Book;
import com.yitong.dao.BookDao;
import java.math.BigDecimal;
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 (?,?,?,?,?,?)";
int add = update(sql, book.getName(), book.getAuthor(), book.getPrice(), book.getSales()
, book.getStock(), book.getImgPath());
return add;
}
@Override
public int deleteBookById(int id) {
String sql = "delete from t_book where id = ?";
int delete = update(sql, id);
return delete;
}
@Override
public int updateBook(Book book) {
String sql = "update t_book set `name`=? ,`author`=?,`price`=?,`sales`=?,`stock`=?,`img_path`=? where id=?";
int add = update(sql, book.getName(), book.getAuthor(), book.getPrice(), book.getSales(), book.getStock(),book.getImgPath(),book.getId());
return add;
}
@Override
public Book queryBookById(int id) {
String sql="select `name`,`author`,`price`,`sales`,`stock`,`img_path` imgPath from t_book where id = ?";
Book book = queryForOne(Book.class, sql, id);
return book;
}
@Override
public List<Book> queryBooks() {
String sql="select `name`,`author`,`price`,`sales`,`stock`,`img_path` imgPath from t_book";
List<Book> books = queryForList(Book.class, sql);
return books;
}
}
BookDao测试类
package com.yitong.test;
import com.yitong.bean.Book;
import com.yitong.dao.BookDao;
import com.yitong.dao.impl.BookDaoImpl;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.List;
public class BookDaoTest {
private BookDao bookDao = new BookDaoImpl();
@Test
public void addBook() {
Book book = new Book(20, "MySQL从入门到入狱", "李四", new BigDecimal(9.99), 9999, 2, "static/img/default.jpg");
int i = bookDao.addBook(book);
System.out.println(i);
}
@Test
public void deleteBookById() {
int i = bookDao.deleteBookById(21);
System.out.println(i);
}
@Test
public void updateBook() {
int i = bookDao.updateBook(new Book(19, "JAVA从入门到跑路", "张三", new BigDecimal(9.99), 9999, 2, "static/img/default.jpg"));
System.out.println(i);
}
@Test
public void queryBookById() {
Book book = bookDao.queryBookById(13);
System.out.println(book);
}
@Test
public void queryBooks() {
List<Book> books = bookDao.queryBooks();
for (Book book : books) {
System.out.println(book);
}
}
}
2.4、编写图书模块Service和测试Service
BookService接口类
package com.yitong.service;
import com.yitong.bean.Book;
import java.util.List;
public interface BookService {
public int addBook(Book book);
public int deleteBook(int id);
public int updateBook(Book book);
public Book queryBookById(int id);
public List<Book> queryBook();
}
BookServiceImpl接口实现类
package com.yitong.service.impl;
import com.yitong.bean.Book;
import com.yitong.dao.BookDao;
import com.yitong.dao.impl.BookDaoImpl;
import com.yitong.service.BookService;
import java.util.List;
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
@Override
public int addBook(Book book) {
bookDao.addBook(book);
return bookDao.addBook(book);
}
@Override
public int deleteBook(int id) {
return bookDao.deleteBookById(id);
}
@Override
public int updateBook(Book book) {
return bookDao.updateBook(book);
}
@Override
public Book queryBookById(int id) {
return bookDao.queryBookById(id);
}
@Override
public List<Book> queryBook() {
return bookDao.queryBooks();
}
}
BookServiceTest测试类
package com.yitong.test;
import com.yitong.bean.Book;
import com.yitong.service.BookService;
import com.yitong.service.impl.BookServiceImpl;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.List;
import static org.junit.Assert.*;
public class BookServiceTest {
private BookService bookService = new BookServiceImpl();
@Test
public void addBook() {
bookService.addBook(new Book(null,"国哥在手,天下我有!", "1125", new BigDecimal(1000000),
100000000,0,null));
}
@Test
public void deleteBook() {
bookService.deleteBook(21);
}
@Test
public void updateBook() {
bookService.updateBook(new Book(42,"国哥在手,天下我有!", "1125", new BigDecimal(1000000),
100000000,0,null));
}
@Test
public void queryBookById() {
System.out.println(bookService.queryBookById(30));
}
@Test
public void queryBook() {
List<Book> books = bookService.queryBook();
for (Book book : books) {
System.out.println(book);
}
}
}
2.5、编写图书模块的WEB层和页面联调测试
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ivzrugaW-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16396228971970.png)]
BaseServlet
package com.yitong.controller;
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 {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
try {
Method declaredMethod = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
declaredMethod.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
BookServlet
package com.yitong.controller;
import com.yitong.bean.Book;
import com.yitong.service.BookService;
import com.yitong.service.impl.BookServiceImpl;
import com.yitong.utils.WebUtils;
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 list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Book> books = bookService.queryBook();
req.setAttribute("books",books);
req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
}
book_manager.jsp
<%@ 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>
<%--静态包含manager管理模块的菜单--%>
<%@include file="/pages/common/manager_menu.jsp"%>
</div>
<div id="main">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<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>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a href="book_edit.jsp">添加图书</a></td>
</tr>
</table>
</div>
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
修改【图书管理】请求地址
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
//修改请求地址
<a href="manager/bookServlet?action=list">图书管理</a>
<a href="pages/manager/order_manager.jsp">订单管理</a>
<a href="index.jsp">返回商城</a>
</div>
前后台请求地址区别
项目一般分为前后台
前台:是给普通用户使用,一般不需要权限检查就可以访问资源,或者功能都属于前台功能。比如淘宝不登陆就可以访问的首页(包含商品浏览)前台地址为:client/bookServlet/
后台:是写给管理员使用的。一般都需要权限检查才能访问到的资源,或页面或功能,是后台。后台的地址为:manager/bookServlet/
2.6、添加图书
? 表单重复提交:当用户提交完请求,浏览器会记录下最后一次请求的全部信息,当用户按F5刷新的时候,数据就会再次提交,浏览器再次发送请求给后台就会再次执行添加操作。
? 点击添加图书按钮,跳转到添加页面,填写完对应信息之后点击提交,执行add方法将数据添加到数据库中。然后通过重定向跳回书籍列表页面。
添加书籍信息页面
<%@ 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"%>
<style type="text/css">
h1 {
text-align: center;
margin-top: 200px;
}
h1 a {
color:red;
}
input {
text-align: center;
}
</style>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="../../static/img/logo.gif" >
<span class="wel_word">编辑图书</span>
<%--静态包含manager管理模块的菜单--%>
<%@include file="/pages/common/manager_menu.jsp"%>
</div>
<div id="main">
<form action="manager/bookServlet" method="get">
<input type="hidden" name="action" value="add">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<tr>
<td><input name="name" type="text" value="时间简史"/></td>
<td><input name="price" type="text" value="30.00"/></td>
<td><input name="author" type="text" value="霍金"/></td>
<td><input name="sales" type="text" value="200"/></td>
<td><input name="stock" type="text" value="300"/></td>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</div>
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
添加图书Servlet
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Book book = WebUtils.copyParamToBean(req.getParameterMap(), new Book());
bookService.addBook(book);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}
2.7、删除图书信息
删除jsp
<%@ 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"%>
<script type="text/javascript">
$(function (){
$("a.deleteclass").click(function (){
//在时间的function函数中,有一个this对象,这个this对象,是当前正在相应事件的dom对象。
/*
* confirm是是确认提示框函数
* 参数是它的提示内容
* 它有两个按钮,一个确认,一个是取消
* 返回true表示点击了确认按钮,返回false表示点击取消
*/
return confirm("你确定要删除" + $(this).parent().parent().find("td:first").text() + "吗?");
});
});
</script>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="../../static/img/logo.gif" >
<span class="wel_word">图书管理系统</span>
<%--静态包含manager管理模块的菜单--%>
<%@include file="/pages/common/manager_menu.jsp"%>
</div>
<div id="main">
<table>
<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 class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
</tr>
</c:forEach>
</table>
</div>
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
删除Servlet
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String id = req.getParameter("id");
int i = WebUtils.parseInt(id, 0);
bookService.deleteBook(i);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}
2.8、修改图书信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGr9Vx0p-1647832234580)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16399641294841.png)]
? jsp页面不能直接携带数据到下一个页面,因此在图书列表管理页面不能直接到图书信息修改页面,它要去数据库中获取当前修改的图书对应信息。所以要经过servlet将数据从数据库中获取出来。展示到页面
2.8.1、将要修改的图书信息展示到修改页面
修改列表页面信息
<%--
a标签中的跳转请求中斜杠的用法
开头加斜杠表示在端口号后面加请求地址
开头不加斜杠表示在工程名后加请求地址
将修改请求的连接改为将要修改的信息展示
--%>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}">修改</a></td>
<td><a class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
</tr>
</c:forEach>
BookServlet程序中添加getBook方法
protected void getBook(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
int id = WebUtils.parseInt(req.getParameter("id"),0);
Book book = bookService.queryBookById(id);
req.setAttribute("book",book);
req.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(req.resp);
}
在book_edit.jsp页面中显示修改的数据
<div id="main">
<form action="manager/bookServlet" method="get">
<input type="hidden" name="action" value="add"/>
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<tr>
<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
<td><input type="submit" value="提交"</td>
</tr>
</table>
</form>
</div>
2.8.2、将修改后的数据存储到数据库并跳回图书列表页面
遇到的问题是:book_edit.jsp页面,既要做添加此操作又要做修改操作。。而到底是添加还是修改是由一个隐藏域来决定的。如何动态修改隐藏域让它的值即可实现添加。又可以实现修改操作
解决方案一:可以在请求发起时,附带上当前要操作的值。并注入到隐藏域中。
book_manager.jsp
<div id="main">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<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>
<%--
a标签中的跳转请求中斜杠的用法
开头加斜杠表示在端口号后面加请求地址
开头不加斜杠表示在工程名后加请求地址
--%>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
<td><a class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
</tr>
</c:forEach>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>
</tr>
</table>
</div>
book_edit.jsp
<div id="main">
<form action="manager/bookServlet" method="get">
<%--可以通过请求的method属性来判断这个页面用来复用那个功能--%>
<input type="hidden" name="action" value="${param.method}">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<tr>
<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</div>
解决方案二:可以通过判断当前请求参数中是否包含有id参数,如果有说明是修改操作,如果没有说明是添加操作。
<div id="main">
<form action="manager/bookServlet" method="get">
<%--
判断请求数据的id是否为空,如果为空就为添加信息,不为空就是修改信息
--%>
<input type="hidden" name="action" value="${empty param.id ? "add" : "update"}">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<tr>
<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</div>
解决方案三:可以通过判断,Request域中是否包含有修改的图书信息对象,如果没有说明是添加操作,如果有说明是修改操作。
<div id="main">
<form action="manager/bookServlet" method="get">
<%--
判断request是否为空,如果为空就为添加信息,不为空就是修改信息
--%>
<input type="hidden" name="action" value="${empty requestScope.book ? "add" : "update"}">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<tr>
<td><input name="name" type="text" value="${requestScope.book.name}"/></td>
<td><input name="price" type="text" value="${requestScope.book.price}"/></td>
<td><input name="author" type="text" value="${requestScope.book.author}"/></td>
<td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
<td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
<td><input type="submit" value="提交"/></td>
</tr>
</table>
</form>
</div>
在BookServlet程序中添加update方法
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Map parameterMap = req.getParameterMap();
Book book = WebUtils.copyParamToBean(parameterMap, new Book());
bookService.updateBook(book);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}
在修改图书信息的时候需要id,因此我们在请求update时需要把id传回去,我们把id属性写在隐藏域中,这个时候就可以更新了。
<input type="hidden" name="id" value="${requestScope.book.id}">
3、图书分页分析
3.1、分页模块的分析
由分页的视图分析出分页的对象模型Page模型
pageNo 当前页码
pageTotal 总页码
pageTotalCount 总记录数
pageSize 每页显示数量
items 当前页数据
这些属性的值都怎么确定?
-
pageNo:当前页码是由客户端进行传递 -
pageSize:每页显示数量由两种因素决定
-
pageTotalCount:总记录数可以由sql语句求得。 sql语句是:select count(*) from 表名 -
pageTotal:总页码可以由总记录数/每页数量得到。 注:总记录数%每页的数量>0,则总页码+1 -
item是当前页数据,也可以由sql语句求得。 sql语句的范围都是前闭后开区间,可以理解为1-4就是0-3,类比数组下标。不包含最后一个。 sql:select * from 表名 limit begin , pageSize; begin可以由公式求得:(pageNo-1)x pageSize; 假设,当前是第1页,每页5条记录,则begin = (1-1)x 5 得0; 假设,当前是第2页,每页5条记录,则begin = (2-1)x 5 得5; 假设,当前是第3页,每页5条记录,则begin = (3-1)x 5 得10; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wj7mzJRv-1647832234580)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211220145754282.png)]
|