目录
第一阶段:表单验证
需求
流程
代码实现
第二阶段:用户登录和注册
需求
Java EE项目的三层结构
代码实现
创建书城的数据库和表
编写数据库表对应的JavaBean对象
编写工具类JdbcUtils
编写baseDao
编写UserDao和测试
编写UserService和测试
编写web层
IDEA中Debug调试的使用
用户登录功能的实现
第三阶段
页面jsp动态化
抽取页面中相同的内容
登录,注册错误提示,及表单回显
baseServlet的抽取
第四阶段-图书模块
MVC概念
图书模块
第一阶段:表单验证
需求
验证用户名:必须由字母,数字下划线组成,并且长度为
5
到
12
位
验证密码:必须由字母,数字下划线组成,并且长度为5到
12
位
验证确认密码:和密码相同
邮箱验证:xxxxx@xxx.com
验证码:现在只需要验证用户已输入。因为还没讲到服务器。验证码生成。
流程
1.在idea中新建模块book_static(静态工程)
2.将书城的静态资源拷贝到book_static工程下
流程 1.在idea中新建模块book_static(静态工程) 2.将书城的静态资源拷贝到book_static工程下
分为购物车,后台管理,订单,用户登录注册模块
3.在register.html中实现代码逻辑
代码实现
尚硅谷会员注册页面
.login_form{
height:420px;
margin-top: 25px;
}
欢迎注册
注册尚硅谷会员
尚硅谷书城.Copyright ©2015
第二阶段:用户登录和注册
需求
需求1:用户注册
需求如下:1)访问注册页面
2)填写注册信息,提交给服务器
3)服务器应该保存用户
4)当用户已经存在----提示用户注册 失败,用户名已存在
5)当用户不存在-----注册成功
需求2:用户登陆
需求如下:
1)访问登陆页面
2)填写用户名密码后提交
3)服务器判断用户是否存在
Java EE项目的三层结构
分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。
项目的包分类
web层 com.atguigu.web/servlet/controller
service层 com.atguigu.service Service接口包
com.atguigu.service.impl Service接口实现类
dao持久层 com.atguigu.dao Dao接口包
com.atguigu.dao.impl Dao接口实现类
实体bean对象 com.atguigu.pojo/entity/domain/bean JavaBean 类
测试包 com.atguigu.test/junit
工具类 com.atguigu.utils
IDEA搭建书城项目开发环境
创建动态java工程 file--new--module--勾选Web Application,在web中导入静态文件资源pages,static,index.html,在src下创建对应的包
代码实现创建书城的数据库和表
drop database if exists book;
create database book;
use book;
create table t_user(
`id` int primary key auto_increment,
`username` varchar(20) not null unique,
`password` varchar(32) not null,
`email` varchar(200)
);
insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@atguigu.com');
select * from t_user;
编写数据库表对应的JavaBean对象
public class User {
private Integer id;
private String username;
private String password;
private String email;
...
//使用ctrl+alt+S快速生成get/set,toString方法和构造器
}
编写工具类JdbcUtils
1导入需要的jar(数据库和连接池需要)
druid-1.1.9.jar mysql-connector-java-5.1.7-bin.jar 在WEB-INF文件夹下新建lib文件夹,用于存放jar包.(把相关jar复制进来).添加jar包方法如下: file-project structure 1.2.找到相关的jar包,先不绑定具体的module,更改libraries的名字
3. 把book_lib添加到book工程
4.添加到artifacts中
2.在src源码目录下编写jdbc.properties属性配置文件
username=root password=root url=jdbc:mysql://localhost:3306/book driverClassName=com.mysql.jdbc.Driver initialSize=5 maxActive=10
3.编写JdbcUtils工具类
DruidDataSourceFactory.createDataSource(properties);
public class JdbcUtils {
//创建数据库连接池
private static DruidDataSource dataSource;
static {
try {
Properties properties = new Properties();
// 读取jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中加载数据
properties.load(inputStream);
// 创建数据库连接池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection(){
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
public static void close(Connection conn){
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
4.JdbcUtils测试
public class JdbcUtilsTest {
@Test
public void testJdbcUtils(){
for (int i = 0; i < 100; i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
}
}
编写baseDao
在dao包下,baseDao是复用的,没有具体对象,使用抽象类型
使用dbutils操作数据库,导入DBUtils 的 jar 包 commons-dbutils-1.3.jar。对如下操作陌生的可参考博文JDBC核心技术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 throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return -1;
}
public T queryForOne(Class type,String sql,Object... args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new BeanHandler<>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
public List queryForList(Class type,String sql,Object...args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new BeanListHandler<>(type),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
public Object queryForSinglevalue(String sql,Object...args){
Connection conn = null;
try {
conn = jdbcUtils.getConnection();
return queryRunner.query(conn,sql,new ScalarHandler(),args);
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
jdbcUtils.close(conn);
}
return null;
}
}
编写UserDao和测试
方法都是和用户类需要用到的情境相关
public interface UserDao {
public User queryUserByUsername(String username);
public User queryUserByUsernameAndPassword(String username,String password);
public int saveUser(User user);
}
UserDaoImlp实现类
实现UserDao的方法
public class UserDaoImpl extends baseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ?";
return queryForOne(User.class,sql,username);
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ? and password = ?";
return queryForOne(User.class,sql,username,password);
}
@Override
public int saveUser(User user) {
String sql ="insert into t_user (`username`,`password`,`email`) values(?,?,?)";
return update(sql,user.getUsername(),user.getPassword(),user.getEmail());
}
}
UserDao测试类
自动生成测试类
public class UserDaoImplTest {
UserDao userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if(userDao.queryUserByUsername("admin")==null){
System.out.println("用户名可用");
}else{
System.out.println("用户名已存在");
}
}
@Test
public void queryUserByUsernameAndPassword() {
if ( userDao.queryUserByUsernameAndPassword("admin","admin1234") == null) {
System.out.println("用户名或密码错误,登录失败");
} else {
System.out.println("查询成功");}
}
@Test
public void saveUser() {
System.out.println( userDao.saveUser(new User(null,"wzg168", "123456", "wzg168@qq.com")) );
}
}
编写UserService和测试
service表示业务,一个业务一个方法.(业务包含登录/注册/检查用户是否可用)
UserService接口
public interface UserService {
public void registUser(User user);
public User login(User user);
public boolean existUsername(String username);
}
UserServiceImpl实现类
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void registUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
}
@Override
public boolean existUsername(String username) {
if(userDao.queryUserByUsername(username)==null){
//等于null,没找到表示可用
return false;
}
return true;
}
}
UserService测试
public class UserServiceImplTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null,"bbj168","666666","bbj168@qq.com"));
userService.registUser(new User(null,"abc168","666666","abc168@qq.com"));
}
@Test
public void login() {
System.out.println(userService.login(new User(null, "asd", "123456", null)));
System.out.println(userService.login(new User(null, "abc168", "666666", "abc168@qq.com")));
}
@Test
public void existUsername() {
if(userService.existUsername("abc1608")){
System.out.println("用户名已存在");
}else{
System.out.println("用户名可用");
}
}
}
编写web层 实现用户注册的功能 图解用户注册的流程
修改regist.html和regist_success.html页面
路径的使用:web阶段使用base相对 框架之后使用绝对路径 1 、添加 base 标签2、修改base标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
以下是几个修改的示例:3、修改注册表单的提交地址和请求方式
编写RegistServlet程序
在web包下public class RegistServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 1、获取请求的参数 String username = req.getParameter("username"); String password = req.getParameter("password"); String email = req.getParameter("email"); String code = req.getParameter("code"); // 2、检查 验证码是否正确 === 写死,要求验证码为:abcde if ("abcde".equalsIgnoreCase(code)) { // 3、检查用户名是否可用 if (userService.existsUsername(username)) { System.out.println("用户名[" + username + "]已存在!"); // 跳回注册页面 req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp); } else { // 可用 // 调用Sservice 保存到数据库 userService.registUser(new User(null, username, password, email)); // 跳到注册成功页面 regist_success.html req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp); } } else { System.out.println("验证码[" + code + "]错误"); req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp); } } }IDEA中Debug调试的使用
Debug调试代码,首先需要两个元素:断点+Debug启动服务器
1、断点,只需要在代码需要停的行的左边上单击,就可以添加和取消
2、Debug启动Tomcat运行代码:测试工具栏:
变量窗口
它可以查看当前方法范围内所有有效的变量。
方法调用栈窗口
1、方法调用栈可以查看当前线程有哪些方法调用信息
2、下面的方法调用上一行的方法其他常用调试相关按钮:
其他常用调试相关按钮:
用户登录功能的实现
图解用户登录
修改 login.html 页面和 login_success.html 页面
1、添加 base 标签2、修改base标签对页面中所有相对路径的影响(浏览器F12,哪个报红,改哪个)
以下是几个修改的示例:3、修改 login.html 表单的提交地址和请求方式 LoginServlet 程序public class LoginServlet extends HttpServlet { private UserService userService = new UserServiceImpl(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException { // 1、获取请求的参数 String username = req.getParameter("username"); String password = req.getParameter("password"); //调用userService.login()登录处理业务 User loginUser = userService.login(new User(null, username, password, null)); // 如果等于 null,说明登录 失败! if (loginUser == null) { // 跳回登录页面 req.getRequestDispatcher("/pages/user/login.html").forward(req, resp); } else { //登录成功 //跳到成功页面login_success.html req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp); } } }第三阶段
页面jsp动态化
为了实现页面的反馈效果,将静态html改为jsp
1、在html面顶行添加page指令。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2、修改文件后缀名为:.jsp(右键--refactor--rename)
3、使用IDEA搜索替换.html 为.jsp(edit--find --replace in path),将文件中出现的html内容改为jsp抽取页面中相同的内容
如上内容在多个页面中出现,我们将其抽取出为一个公共的JSP页面然后引用,减少代码维护量
登录成功后的菜单login_success_menu.jsp 欢迎韩总光临尚硅谷书城 我的订单 注销 返回order.jsp/login_success.jsp/cart.jsp/checkout.jsp <%--静态包含登录成功之后的菜单--%> <%@include file="/pages/common/login_success_menu.jsp"%>head 中 css 、 jquery 、 base 标签 每个jsp文件中都改动 <%--静态包含base标签,css样式,iquery文件--%> <%@include file="/pages/common/head.jsp"%>每个页面的页脚
尚硅谷书城.Copyright ©2015每个jsp页面 <%--静态包含页脚内容--%> <%@include file="/pages/common/footer.jsp"%>manager模块的菜单
图书管理 订单管理 返回商城<%--静态包含manage管理模块的菜单--%> <%@include file="/pages/common/manage_menu.jsp"%>动态的base标签值
header.jsp
<% String basePath = request.getScheme() +"://" + request.getServerName() +":" +request.getServerPort() +request.getContextPath() +"/"; %>登录,注册错误提示,及表单回显
以登录回显为示例:Servlet程序端需要添加回显信息到Request域中
login.servlet
jsp页面,需要输出回显信息
login.jsp
使用 EL 表达式修改表单回显
以登录为示例
注册模块修改同上
baseServlet的抽取 在实际的项目开发中,一个模块,一般只使用一个 Servlet 程序。此处的登录注册模块合并为一个UserServlet. 代码优化一:代码优化:合并 LoginServlet 和 RegistServlet 程序为 UserServlet 程序
UserServlet 程序:public class UserServlet extends HttpServlet { UserService userService = new UserServiceImpl(); protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); User loginUser = userService.login(new User(null, username, password, null)); //如果等于null,说明登录失败 if(loginUser == null){ //把错误信息和回显的表单项信息,保存到request域中 request.setAttribute("msg","用户名或密码错误"); request.setAttribute("username",username); //跳回登录页面 request.getRequestDispatcher("/pages/user/login.jsp").forward(request,response); }else{ //登录成功 //跳到成功页面 request.getRequestDispatcher("/pages/user/login_success.jsp").forward(request,response); } } protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1.获取请求的参数 String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); String code = request.getParameter("code"); //2.检查验证码是否正确 此处写死,要求验证码是abcde if("abcde".equalsIgnoreCase(code)){ //正确,检查用户是否可用 if(!userService.existUsername(username)){ //可用,调用service保存到数据库,跳到注册成功页面 regist_success.jsp userService.registUser(new User(null,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("用户名已存在"); request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response); } }else{ //不正确,跳回注册页面 request.setAttribute("msg","验证码错误"); request.setAttribute("username",username); request.setAttribute("email",email); System.out.println("验证码错误"); request.getRequestDispatcher("/pages/user/regist.jsp").forward(request,response); } } @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); } } }还要给 login.jsp 添加隐藏域和修改请求地址
给 regist.jsp 页面添加隐藏域 action,和修改请求地址
优化代码二:使用反射优化大量 else if 代码:
如果用户模块有多个功能(除登录注册外),如添加,修改,注销等,那么Userservlet程序会增加多个elseif 来判断执行哪个功能的代码。通过反射获取对应的方法执行,不需要再判断。
@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); try { //获取action业务鉴别字符串,获取相应的业务方法反射对象 Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); //调用业务目标方法 method.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); } } }代码优化三:抽取 baseServlet 程序
servlet程序中含有相同功能的代码块,我们将其抽取出来放入baseServlet
baseServlet.java
public abstract class baseServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String action = req.getParameter("action"); try { Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class); method.invoke(this, req, resp); } catch (Exception e) { e.printStackTrace(); } } }修改UserServlet程序继承baseServlet程序
public class UserServlet extends baseServlet { ... ... }数据的封装和抽取BeanUtils的使用
BeanUtils 工具类,它 可以一次性的把所有请求的参数注入到JavaBean 中。 BeanUtils.populate(user, request.getParameterMap()); 减少如下代码的使用//1.获取请求的参数 String username = request.getParameter("username"); String password = request.getParameter("password"); String email = request.getParameter("email"); String code = request.getParameter("code"); userService.registUser(new User(null,username,password,email));BeanUtils工具类,经常用于把Map中的值注入到JavaBean中,或者是对象属性值的拷贝操作。
BeanUtils它不是Jdk的类。而是第三方的工具类。所以需要导包。
1、导入需要的 jar 包:
commons-beanutils-1.8.0.jar
commons-logging-1.1.1.jar使用BeanUtils类方法实现注入(此方法可省略之前的getParameter接收和注入)
try { User user = new User(); System.out.println("注入之前"+user); //把所有请求的参数注入到user对象中 //参数object和 java.util.Map BeanUtils.populate(user, request.getParameterMap()); System.out.println("注入之后"+user); } catch (Exception e) { e.printStackTrace(); }将上述代码写成工具类封装
2、编写WebUtils(代码封装)版本1.0
public class WebUtils { public static void copyParmToBean(HttpServletRequest request,Object bean){ try { System.out.println("注入之前"+bean); //把所有请求的参数注入到bean对象中 BeanUtils.populate(bean, request.getParameterMap()); System.out.println("注入之后"+bean); } catch (Exception e) { e.printStackTrace(); } } }参数注入的底层原理
User user = new User(); WebUtils.copyParmToBean(request,user);action=[regist]
username=[sadfs342]
password=[121212]
repwd=[121212]
email=[sddsa@qq.com]
code=[abcde]可以发现上述的参数名和User类中的属性名对应。map中取到XX参数,通过参数找到setXX方法,然后赋值。
public static void copyParmToBean(HttpServletRequest request,Object bean){ BeanUtils.populate(bean, request.getParameterMap());是将map的值注入到JavaBean中 }对参数进行改进
public static void copyParmToBean(Map value,Object bean){ BeanUtils.populate(bean, value);是将map的值注入到JavaBean中 }将map注入javabean而不是request注入的原因是:HTTPServletRequest不适用于Dao层和Web层,会带来耦合,而Map层则是通用的。
改进:
User user = new User(); WebUtils.copyParmToBean(request.getParameterMap(),user); 改写成 User user = (User)WebUtils.copyParmToBean(request.getParameterMap(),new User()); public class WebUtils { public static Object copyParmToBean(Map value, Object bean){ try { System.out.println("注入之前"+bean); //把所有请求的参数注入到bean对象中 BeanUtils.populate(bean, value); System.out.println("注入之后"+bean); } catch (Exception e) { e.printStackTrace(); } return bean; } }使用泛型改进
public class WebUtils { public staticT 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; } } 第四阶段-图书模块
MVC概念
MVC全称:Model模型、View视图、Controller控制器。MVC最早出现在JavaEE三层中的Web 层,它可以有效的指导Web层的代码如何有效分离,单独工作。
View视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML。
Controller控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。派发页面主要指转到某个页面。或者是重定向到某个页面。
Model模型:将与业务逻辑相关的数据封装为具体的JavaBean类,其中不掺杂任何与数据处理相关的代码——JavaBean/domain/entity/pojo。
MVC是一种思想
MVC的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)。MVC 的作用还是为了降低耦合。让代码合理分层。方便后期升级和维护。
图书模块
编写图书模块的数据库表
## 创建图书表 create table t_book( `id` int(11) primary key auto_increment, ## 主键 `name` varchar(50) not null, ## 书名 `author` varchar(50) not null, ## 作者 `price` decimal(11,2) not null, ## 价格 `sales` int(11) not null, ## 销量 `stock` int(11) not null, ## 库存 `img_path` varchar(200) not null ## 书的图片路径 ); ## 插入初始化测试数据 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;编写图书模块的JavaBean
Book.java
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 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; } } ....... }编写图书模块的Dao和测试Dao
BookDao.java
public interface BookDao { public int addBook(Book book); public int deleteBookById(Integer id); public int updateBook(Book book); public Book queryById(Integer id); public ListqueryBooks(); } baseDaoImpl.java
BookDaoTest.java
public class BookDaoTest { BookDao bookDao = new BookDaoImpl(); @Test public void addBook() { bookDao.addBook(new Book(null,"十万个为什么","yuyu",new BigDecimal(999),131,0,null)); } @Test public void deleteBookById() { bookDao.deleteBookById(21); } @Test public void updateBook() { bookDao.updateBook(new Book(22,"十万个我知道","yanglin",new BigDecimal(999),131,0,null)); } @Test public void queryById() { System.out.println(bookDao.queryById(22)); } @Test public void queryBooks() { for(Book book:bookDao.queryBooks()){ System.out.println(book); } } }编写图书模块的Service和测试Service
BookService.java
public interface BookService { public void addBook(Book book); public void deleteBookById(Integer id); public void updateBook(Book book); public Book queryBookById(Integer id); public ListqueryBooks(); } BookServiceImpl.java
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.queryById(id); } @Override public ListqueryBooks() { return bookDao.queryBooks(); } } BookServiceTest.java
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 deleteBookById() { bookService.deleteBookById(22); } @Test public void updateBook() { bookService.updateBook(new Book(22,"社会我国哥,人狠话不多!", "1125", new BigDecimal(999999), 10, 111110, null)); } @Test public void queryBookById() { System.out.println(bookService.queryBookById(22)); } @Test public void queryBooks() { for (Book queryBook : bookService.queryBooks()) { System.out.println(queryBook); } }编写图书模块的Web层和页面联调测试
最后得到的效果
BookServlet程序中添加list方法
protected void List(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //1.通过BookService查询全部图书 Listbooks = bookService.queryBooks(); //2.把查询结果保存再Request域中 req.setAttribute("books",books); //3.请求转发到/pages/manager/book_manager.jsp页面 req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp); } 修改图书管理的请求地址
manage_menu.jsp
修改book_manager.jsp页面的数据遍历输出
调试的时候出现405的原因是a标签是get请求,而代码里是post。解决方法是再baseServlet添加doGet方法。
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> ... ...
| 名称 | 价格 | 作者 | 销量 | 库存 | 操作 | |
| ${book.name} | ${book.price} | ${book.author} | ${book.sales} | ${book.stock} | 修改 | 删除 |
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
前后台的简单介绍
xml配置文件中
添加图书功能的实现
添加图书流程细节:
BookServlet程序中添加add方法
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.获取参数的请求==封装成Book对象
Book book = WebUtils.copyParmToBean(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");
}
问题说明:表单重复提交:当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户按下功能键 F5,就会发起浏览器记录的最后一次请求。(重定向是二次请求,请求转发是一次请求)
修改book_edit.jsp页面



