所有的网页开发都需要遵守MVC设计模式,M表示Model,V表示View,C表示Controller(控制器)。
Servlet(控制层)调用service(业务层)调用dao(接口层)
控制层:接受请求参数,响应前端数据。几个业务写几个service和几个service实现类。
以后开发中,JSP中不允许连接数据库。在JSP中看不到java代码,在servlet中看不到html代码。
MVC模式:M(model模型)V(view视图)C(controller控制器)
显示层(view):JSP显示页面,不允许有Java代码
控制层(servlet):servlet就是一个java类,可编写大量的java代码,但是很难显示页面。
数据模型(model)dao操作数据库,dao就是一个Java Bean组件,可以重复使用。
除了dao和mvc还有业务层service。
Dao数据访问层或持久化层,进行数据库的数据操作。
客户层:客户端浏览器;显示层:用JSP进行页面渲染;
控制层:servlet连接显示层和业务层;业务层:service层,连接控制层和持久化层,并进行业务处理,如事务;
持久化层:数据访问层,由JDBC完成。
1.两种开发模式
在实际的开发中,有两种模式:
- 模式一:像最早学习JSP语法基础的时候,将显示,数据操作都放在JSP中完成,没有任何的DAO,没有任何架构,
像我们最早的登录程序,loginCheck.jsp中就进行了数据库的校验操作,这种代码的开发,效率非常高,
但是缺点也很明显:代码的耦合度非常高,JSP中存在大量的Java代码,JSP和JAVA代码耦合在一起,很难进行维护。
- 优点:开发效率高,优点类似于php或者asp开发
- 缺点:代码的耦合度很高,jsp中的html代码和Java代码紧密的耦合在一起,造成程序的可读性可维护性很低。
- 模式二:在实际的开发中,几乎都使用MVC设计模式,实际上就是将显示、控制和数据模型相分离:
- 显示层View: jsp:显示非常简单,因为里面可以直接编写html代码,
- 控制层Controller:servlet:本身就是一个Java类,所以可以任意多的编写Java代码,但是显示非常苦难
- 数据模型Model:dao:生产数据模型,就是一个JavaBean的组件,可以重复调用
以后的开发中,就是在JSP中看不到任何实际的Java代码,在Servlet中看不到任何实际的HTML代码,
目前市场上比较流行的MVC框架:
- Struct1:已经N多年没有用过了,并且也没有企业在用。
- Struct2:有巨大的漏洞,现在企业最多10%再用。
- SpringMVC:是目前最流行的MVC框架,并且适用于互联网的RestFul风格的开发
2.MVC的实现
除了DAO和MVC之外,我们还存在一层叫做业务层,不属于DAO和MVC,是独立出来进行业务处理的。
学习了DAO和MVC之后,以后的程序中,JSP是绝对不允许再连接数据库的。
以后的开发中,就是在JSP中看不到任何实际的Java代码,在Servlet中看不到任何实际的HTML代码。
控制层调用业务层,业务层调用dao层。
用户登入和查看图书信息
package com.wanbangee.util;
import java.sql.Connection;
import java.sql.DriverManager;
public class MySQLUtil {
public final static String DRIVER = "com.mysql.jdbc.Driver";
public final static String URL = "jdbc:mysql://127.0.0.1:3306/buybook";
public final static String USER = "root";
public final static String PASSWORD = "3306";
public static Connection getConnection() throws Exception {
Connection conn = null;
//2 加载驱动程序[实现了JDBC标准接口的MySQL实现程序]
Class.forName(DRIVER);
//3取得数据库连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
return conn;
}
}
package com.wanbangee.entities;
public class Account {
private Integer accId;
private String accName;
private String accPass;
private Double accBalance;
public Integer getAccId() {
return accId;
}
public void setAccId(Integer accId) {
this.accId = accId;
}
public String getAccName() {
return accName;
}
public void setAccName(String accName) {
this.accName = accName;
}
public String getAccPass() {
return accPass;
}
public void setAccPass(String accPass) {
this.accPass = accPass;
}
public Double getAccBalance() {
return accBalance;
}
public void setAccBalance(Double accBalance) {
this.accBalance = accBalance;
}
public Account(Integer accId, String accName, String accPass, Double accBalance) {
super();
this.accId = accId;
this.accName = accName;
this.accPass = accPass;
this.accBalance = accBalance;
}
public Account() {
super();
// TODO Auto-generated constructor stub
}
}
package com.wanbangee.entities;
public class BookInfo {
private Integer bookNo;
private String bookName;
private Double bookPrice;
private Integer stockId;
private BookStock bookStock;
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getBookPrice() {
return bookPrice;
}
public void setBookPrice(Double bookPrice) {
this.bookPrice = bookPrice;
}
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public BookStock getBookStock() {
return bookStock;
}
public void setBookStock(BookStock bookStock) {
this.bookStock = bookStock;
}
public BookInfo(Integer bookNo, String bookName, Double bookPrice, Integer stockId) {
super();
this.bookNo = bookNo;
this.bookName = bookName;
this.bookPrice = bookPrice;
this.stockId = stockId;
}
public BookInfo() {
super();
// TODO Auto-generated constructor stub
}
}
package com.wanbangee.entities;
public class BookStock {
private Integer stockId;
private Integer bookNo;
private Integer stockNum;
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public Integer getStockNum() {
return stockNum;
}
public void setStockNum(Integer stockNum) {
this.stockNum = stockNum;
}
public BookStock(Integer stockId, Integer bookNo, Integer stockNum) {
super();
this.stockId = stockId;
this.bookNo = bookNo;
this.stockNum = stockNum;
}
public BookStock() {
super();
// TODO Auto-generated constructor stub
}
}
package com.wanbangee.dao;
import com.wanbangee.entities.Account;
public interface AccountDao {
//登入:根据用户名和密码返回用户对象
public Account selectAccountByaccNameAndaccPass(String accName,String accPass);
}
package com.wanbangee.dao;
import java.util.List;
import com.wanbangee.entities.BookInfo;
public interface BookInfoDao {
//查询所有图书信息,用集合来存储
public List<BookInfo> selectBookInfo();
}
package com.wanbangee.dao;
import com.wanbangee.entities.BookStock;
public interface BookStockDao {
//根据库存ID查看库存信息,返回一笔数据为库存信息
public BookStock selectBookStockByStockId(Integer stockId);
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entities.Account;
public class AccountDaoImp implements AccountDao {
private Connection conn;
public AccountDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public Account selectAccountByaccNameAndaccPass(String accName, String accPass) {
Account account = null;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select acc_id,acc_name,acc_balance from account where acc_name = ? and acc_pass = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, accName);
pstate.setString(2, accPass);
res = pstate.executeQuery();
while(res.next()) {
//不能把密码加进来
//Account account = new Account(accId, accName, accPass, accBalance)
//account = new Account(res.getInt(1), res.getString(2), null, res.getDouble(3));
account = new Account();
account.setAccId(res.getInt("acc_id"));
account.setAccName(res.getString("acc_name"));
account.setAccBalance(res.getDouble("acc_balance"));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return account;
}
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.entities.BookInfo;
public class BookInfoDaoImp implements BookInfoDao {
private Connection conn;
public BookInfoDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public List<BookInfo> selectBookInfo() {
//查询所有图书信息,用集合来存储
List<BookInfo> bookInfos = new ArrayList<>();
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select book_no,book_name,book_price,stock_id from book_info ";
pstate = this.conn.prepareStatement(sql);
res = pstate.executeQuery();
while(res.next()) {
BookInfo bookInfo = new BookInfo(res.getInt("book_no"), res.getString(2), res.getDouble(3), res.getInt(4));
bookInfos.add(bookInfo);//将对象添加到集合中
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return bookInfos;
}
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.entities.BookInfo;
import com.wanbangee.entities.BookStock;
public class BookStockDaoImp implements BookStockDao {
private Connection conn;
public BookStockDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public BookStock selectBookStockByStockId(Integer stockId) {
BookStock bookStock = null;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select stock_id,stock_num,book_no from book_stock where stock_id = ? ";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, stockId);
res = pstate.executeQuery();
while(res.next()) {
bookStock = new BookStock(res.getInt(1), res.getInt(2), res.getInt(3));
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return bookStock;
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.dao.imp.AccountDaoImp;
public class AccountDaoFactory {
public static AccountDao getAccountDaoInstance(Connection conn) {
return new AccountDaoImp(conn);
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.dao.imp.BookInfoDaoImp;
public class BookInfoDaoFactory {
public static BookInfoDao getBookInfoDaoInstance(Connection conn) {
return new BookInfoDaoImp(conn);
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.dao.imp.BookStockDaoImp;
public class BookStockDaoFactory {
public static BookStockDao getBookStockDaoInstance(Connection conn) {
return new BookStockDaoImp(conn);
}
}
package com.wanbangee.service;
import com.wanbangee.entities.Account;
public interface LoginService {
//登入业务
public Account login(String accName,String accPass);
}
package com.wanbangee.service;
import java.util.List;
import com.wanbangee.entities.BookInfo;
public interface BookService {
//查看所有图书信息业务
public List<BookInfo> selectBookInfo();
//买书业务
public boolean buyBook(Integer accId,Integer bookNo);
}
package com.wanbangee.service.imp;
import java.sql.Connection;
import com.wanbangee.dao.factory.AccountDaoFactory;
import com.wanbangee.entities.Account;
import com.wanbangee.service.LoginService;
import com.wanbangee.util.MySQLUtil;
public class LoginServiceImp implements LoginService {
@Override
public Account login(String accName, String accPass) {
Account account = null;
Connection conn = null;
try {
conn = MySQLUtil.getConnection();
account = AccountDaoFactory.getAccountDaoInstance(conn).selectAccountByaccNameAndaccPass(accName, accPass);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return account;
}
}
package com.wanbangee.service.imp;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import com.wanbangee.dao.factory.BookInfoDaoFactory;
import com.wanbangee.dao.factory.BookStockDaoFactory;
import com.wanbangee.entities.BookInfo;
import com.wanbangee.service.BookService;
import com.wanbangee.util.MySQLUtil;
public class BookServiceImp implements BookService {
//查看图书信息业务
@Override
public List<BookInfo> selectBookInfo() {
Connection conn = null;
List<BookInfo> bookInfos = null;
try {
conn = MySQLUtil.getConnection();
bookInfos = BookInfoDaoFactory.getBookInfoDaoInstance(conn).selectBookInfo();
for (BookInfo bookInfo : bookInfos) {//将遍历到的查询结果放到集合中
bookInfo.setBookStock(BookStockDaoFactory.getBookStockDaoInstance(conn).selectBookStockByStockId(bookInfo.getStockId()));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return bookInfos;
}
//买书业务
@Override
public boolean buyBook(Integer accId, Integer bookNo) {
return false;
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.wanbangee.entities.Account;
import com.wanbangee.service.BookService;
import com.wanbangee.service.LoginService;
import com.wanbangee.service.imp.BookServiceImp;
import com.wanbangee.service.imp.LoginServiceImp;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String username = request.getParameter("username");
String password = request.getParameter("password");
String path = request.getContextPath();
//根据用户名密码查询数据库
LoginService loginService = new LoginServiceImp();
Account account = loginService.login(username, password);
if(null != account) {
//登录成功
//将用户信息设置到session域中
HttpSession session = request.getSession();
session.setAttribute("account", account);
//查询图书信息,将图书信息加入到request请求域中
BookService bookService = new BookServiceImp();
request.setAttribute("bookInfos", bookService.selectBookInfo());//将图书数据加入到请求域中
request.getRequestDispatcher("/jsp/books.jsp").forward(request, response);//转发
}else {
//跳转到登录失败页面
response.sendRedirect(path+"/jsp/fail.jsp");//重定向
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String path = request.getContextPath();
%>
<form action="<%= path %>/LoginServlet" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>登录失败,请重新<a href="login.jsp">登录</a></h1>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
session.invalidate();//session失效
response.sendRedirect("login.jsp");//重定向
//logout.jsp和login.jsp在同一目录
%>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*,com.wanbangee.entities.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="<%=request.getContextPath()%>/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){//给注销按钮添加单击事件
$("#logout").click(function(event){
event.preventDefault();//取消组件的默认行为
if(confirm("确认注销登录吗?")){
var href = $(this).attr("href");
//在href属性中获得超链接地址
//jQuery中attr("href")函数根据属性名取得属性值
window.location.href = href;//执行重定向
}
//return false;//取消超链接的默认行为
});
});
</script>
</head>
<body>
<%
Account account = (Account)session.getAttribute("account");//得到的是Object类型
List<BookInfo> bookInfos = (List<BookInfo>)request.getAttribute("bookInfos");
String path = request.getContextPath();
%>
<h2>登录成功,欢迎您:<%= account.getAccName() + ",您的账户余额为:" + account.getAccBalance()%> <a id="logout" href="<%=path %>/jsp/logout.jsp">注销</a></h2>
<table border="1">
<caption>图书信息列表</caption>
<tr>
<th>图书ID</th>
<th>图书名</th>
<th>图书单价</th>
<th>图书库存</th>
<th>操作</th>
</tr>
<%
for(BookInfo bookInfo:bookInfos){
%>
<tr>
<td><%=bookInfo.getBookNo() %></td>
<td><%=bookInfo.getBookName() %></td>
<td><%=bookInfo.getBookPrice() %></td>
<td><%=bookInfo.getBookStock().getStockNum() %></td>
<!-- 获得BookStock对象 -->
<td><a href="javascript:;">购买</a></td>
<!-- javascript:;用#代替一样的效果,都是没有跳转效果 -->
</tr>
<%
}
%>
</table>
</body>
</html>
监听最常用的操作就是进在线用户的列表操作,查看在线用户列表。
·监听最常用的操作就是进在线用户的列表操作,查看在线用户列表。
·把所有的登陆的用户保存到application范围属性中,属性内容是一个List集合
·如果用户进行注销,则移除此用户
和new个class一样new个监听器Listener,next选择相应对象的changes to attributes实现监听接口。
在servlet包中加个监听器取名为OnLineListener
package com.wanbangee.servlet;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import com.wanbangee.entities.Account;
@WebListener
public class OnLineListener implements HttpSessionAttributeListener,HttpSessionListener,ServletContextListener {
//List<Account> accounts = null;//保存在线用户列表,设置全局变量没有用,每次用户重新登入都要重新取得在线用户列表
ServletContext application;//把application对象设置为全局的,在这些方法中就都能使用
//用户登入,触发attributeAdded方法执行,
public void attributeAdded(HttpSessionBindingEvent event) {
Account account = (Account) event.getValue();
//登入时将account对象放入session域中
//当session域信息设置时,取得设置的值
List<Account> accounts = (List<Account>) application.getAttribute("onlines");//每次用户重新登入都要重新取得在线用户列表
accounts.add(account);//用户登入时将登入的用户信息添加到在线用户列表
application.setAttribute("onlines", accounts);//再次设置到application域中
//每次用户登入都能保证application域中用户列表是最新的
}
//用户注销时,session域信息移除
//session注销要实现HttpSessionListener接口
public void attributeRemoved(HttpSessionBindingEvent event) {
//Account account = (Account) event.getValue();
//当session域信息移除时,取得设置的值
}
public void attributeReplaced(HttpSessionBindingEvent event) {
}
@Override
public void sessionCreated(HttpSessionEvent event) {
// session创建不管,只管session注销
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
//实现HttpSessionListener接口,获得session注销的信息
HttpSession session = event.getSession();//取得注销的session
List<Account> accounts = (List<Account>) application.getAttribute("onlines");//每次用户注销都要重新取得在线用户列表
Account account = (Account)session.getAttribute("account");//注销session前先取得account用户信息
accounts.remove(account);//用户注销时,将注销的用户移除出在线用户列表
application.setAttribute("onlines", accounts);//再次设置到application域中
}
@Override
public void contextDestroyed(ServletContextEvent event) {
}
@Override
public void contextInitialized(ServletContextEvent event) {
// 实现ServletContextListener接口,监听服务器的启动和销毁
//把用户信息放入application域,让所有用户信息取到信息(session域只是当前用户取得,一旦浏览器关闭或重启就取不到了)
//List<Account> accounts = null;//保存在线用户列表
List<Account> accounts = new ArrayList<>();//服务器启动时把集合实例化出来
application = event.getServletContext();//获得application对象
application.setAttribute("onlines", accounts);//将在线用户列表设置进application域中
}
}
books.jsp更改下代码,显示在线用户列表
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*,com.wanbangee.entities.*" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){//给注销按钮添加单击事件
$("#logout").click(function(event){
event.preventDefault();//取消组件的默认行为
if(confirm("确认注销登录吗?")){
var href = $(this).attr("href");
//在href属性中获得超链接地址
//jQuery中attr("href")函数根据属性名取得属性值
window.location.href = href;//执行重定向
}
//return false;//取消超链接的默认行为
});
});
</script>
</head>
<body>
<%
Account account = (Account)session.getAttribute("account");//得到的是Object类型
List<BookInfo> bookInfos = (List<BookInfo>)request.getAttribute("bookInfos");
String path = request.getContextPath();
List<Account> accounts = (List<Account>) application.getAttribute("onlines");//每次用户登入成功都要重新取得在线用户列表
%>
<h2>登录成功,欢迎您:<%= account.getAccName() + ",您的账户余额为:" + account.getAccBalance()%> <a id="logout" href="${pageContext.request.contextPath}/jsp/logout.jsp">注销</a></h2>
<table border="1">
<caption>图书信息列表</caption>
<tr>
<th>图书ID</th>
<th>图书名</th>
<th>图书单价</th>
<th>图书库存</th>
<th>操作</th>
</tr>
<%
for(BookInfo bookInfo:bookInfos){
%>
<tr>
<td><%=bookInfo.getBookNo() %></td>
<td><%=bookInfo.getBookName() %></td>
<td><%=bookInfo.getBookPrice() %></td>
<td><%=bookInfo.getBookStock().getStockNum() %></td>
<!-- 获得BookStock对象 -->
<td><a href="javascript:;">购买</a></td>
<!-- javascript:;用#代替一样的效果,都是没有跳转效果 -->
</tr>
<%
}
%>
</table>
<hr/>
<h3>在线用户列表</h3>
<ul>
<!-- 循环在线用户的集合 -->
<%
for(Account acc: accounts){
%>
<li><%= acc.getAccName() %></li>
<%
}
%>
</ul>
</body>
</html>
在jsp中使用EL表达式减少了JSP中的java代码,一定要导包,和引入标签库
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*,com.wanbangee.entities.*" %>
<!-- 导入标签库 : 导入jstl的核心库,prefix前缀-->
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){
$("#logout").click(function(event){
event.preventDefault();//取消组件的默认行为
if(confirm("确认注销登录吗?")){
var href = $(this).attr("href");
window.location.href = href;//执行重定向
}
//return false;//取消超链接的默认行为
});
});
</script>
</head>
<body>
<!--<h3>${bookInfos}</h3>取得集合,但循环不了集合-->
<!-- 取得集合中某个元素 并且获得此元素的bookName属性-->
<h3>${bookInfos[0].bookName}</h3>
<h2>登录成功,欢迎您:${account.accName},您的账户余额为:${account.accBalance}<a id="logout" href="${pageContext.request.contextPath}/jsp/logout.jsp">注销</a></h2>
<table border="1">
<caption>图书信息列表</caption>
<tr>
<th>图书ID</th>
<th>图书名</th>
<th>图书单价</th>
<th>图书库存</th>
<th>操作</th>
</tr>
<!--
遍历El表达式取到的集合 bookInfos ,每次循环取得集合中的某个数据赋值给bookInfo
c:forEach : 遍历标签
- iteams : 遍历的是哪个集合,通过EL表达式获取集合中的域对象或者其他的信息
- var : 指定遍历集合的每个元素要赋值的变量
- begin : 指定集合从什么位置开始遍历,默认是0
- end : 指定集合遍历结束的位置,默认是集合长度-1
- step : 步长,每次遍历相隔的数量,默认是1
- varStatus : 遍历状态,可以从此状态中获得到遍历的元素在集合中的索引
遍历集合的状态复制给新的变量,可以获取index,fist,last 等等信息
-->
<c:forEach var="bookInfo" items="${bookInfos}" varStatus="status">
<tr>
<td>${bookInfo.bookNo }</td>
<td>${bookInfo.bookName }</td>
<td>${bookInfo.bookPrice }</td>
<td>${bookInfo.bookStock.stockNum }</td>
<td><a href="javascript:;"> ${status.index}</a></td>
</tr>
</c:forEach>
</table>
<hr/>
<h3>在线用户列表</h3>
<ul>
<c:forEach items="${onlines }" var="account">
<li>${account.accName }</li>
</c:forEach>
</ul>
</body>
</html>
用户注册操作,用户注册信息为:
- 用户名
- 密码
- 头像
要求:
1. 需要两次输入密码,并且两次密码必须相同,在js中验证
2. 上传的头像要求保存在pic目录中,在根目录WebContent下new个pic目录用来存放上传的头像
3. 要求上传头像的文件命名为,客户端IP+时间戳+三位0-9之间随机数.后缀 ,比如1270011607849864318056.jpg
这样是ipv4地址形式,用localhost所访问的是ipv6的地址,用127.0.0.1所访问的是ipv4的地址
4. 注册完成,要求数据表account新增一笔数据,数据列acc_pic 存储是用户注册的头像信息(保存头像图片的路径)
数据表account有5个字段,acc_id自增,acc_name,acc_pass,acc_balance默认为0,acc_pic
package com.wanbangee.util;
import java.sql.Connection;
import java.sql.DriverManager;
public class MySQLUtil {
public final static String DRIVER = "com.mysql.jdbc.Driver";
public final static String URL = "jdbc:mysql://127.0.0.1:3306/buybook?useUnicode=true&characterEncoding=utf-8";
public final static String USER = "root";
public final static String PASSWORD = "3306";
public static Connection getConnection() throws Exception {
Connection conn = null;
//2 加载驱动程序[实现了JDBC标准接口的MySQL实现程序]
Class.forName(DRIVER);
//3取得数据库连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
return conn;
}
}
package com.wanbangee.util;
//此方法为获得新文件名,客户端IP+时间戳+三位0-9之间随机数.后缀
import javax.servlet.http.HttpServletRequest;
public class NewFileName {
//要取得客户端ip,得有request对象
public static String getNewFileName(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
//要进行字符串的追加用StringBuffer,String效率比较低
//取得客户端ip
//String remoteAddr = request.getRemoteAddr();
//request.getRemoteAddr()可能是ipv4或ipv6地址
//用localhost所访问的是ipv6的地址,用127.0.0.1所访问的是ipv4的地址
//ipv6地址是以冒号:分割的,ipv4地址是以点.分割,所以取得地址时要移除冒号:和点.
String remoteAddr = request.getRemoteAddr().replaceAll(":", "").replaceAll("\\.", "");
//replaceAll("\\.", "")和split("\\.")一样,也是支持正则的方法,.要加转义字符
sb.append(remoteAddr);
//取得时间戳
Long currentTime = System.currentTimeMillis();
sb.append(currentTime);
//取得三位0-9之间随机数
for (int i = 0; i < 3; i++) {
int random = (int) Math.round(Math.random()*9);//Math.round()四舍五入方法结果为long型,要强转为int
sb.append(random);
}
//把它们全部追加到StringBuffer对象sb,最后return这个StringBuffer对象sb
return sb.toString();
}
}
package com.wanbangee.entities;
public class Account {
private Integer accId;
private String accName;
private String accPass;
private Double accBalance;
private String accPic;
public String getAccPic() {
return accPic;
}
public void setAccPic(String accPic) {
this.accPic = accPic;
}
public Integer getAccId() {
return accId;
}
public void setAccId(Integer accId) {
this.accId = accId;
}
public String getAccName() {
return accName;
}
public void setAccName(String accName) {
this.accName = accName;
}
public String getAccPass() {
return accPass;
}
public void setAccPass(String accPass) {
this.accPass = accPass;
}
public Double getAccBalance() {
return accBalance;
}
public void setAccBalance(Double accBalance) {
this.accBalance = accBalance;
}
public Account(Integer accId, String accName, String accPass, Double accBalance, String accPic) {
super();
this.accId = accId;
this.accName = accName;
this.accPass = accPass;
this.accBalance = accBalance;
this.accPic = accPic;
}
public Account() {
super();
}
}
package com.wanbangee.dao;
import com.wanbangee.entities.Account;
public interface AccountDao {
//新增操作,将注册的一个用户信息插入到数据库中,实体类的一个对象就是表的一笔数据
public void insertAccount(Account account);
}
package com.wanbangee.factory;
import java.sql.Connection;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.imp.AccountDaoImp;
public class AccountDaoFactory {
public static AccountDao getAccountDaoInstance(Connection conn) {
return new AccountDaoImp(conn);
}
}
package com.wanbangee.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entities.Account;
public class AccountDaoImp implements AccountDao {
private Connection conn;
public AccountDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public void insertAccount(Account account) {
PreparedStatement pstate = null;
try {//acc_id自增,acc_balance默认为0,都不用管
String sql = "insert into account(acc_name,acc_pass,acc_pic) values(?,?,?)";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, account.getAccName());
pstate.setString(2, account.getAccPass());
pstate.setString(3, account.getAccPic());
pstate.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
package com.wanbangee.service;
import com.wanbangee.entities.Account;
public interface RegisterService {
//注册信息业务
public void register(Account account);
}
//控制层调用业务层,业务层调用数据访问层
package com.wanbangee.service.imp;
import java.sql.Connection;
import java.sql.SQLException;
import com.wanbangee.entities.Account;
import com.wanbangee.factory.AccountDaoFactory;
import com.wanbangee.service.RegisterService;
import com.wanbangee.util.MySQLUtil;
public class RegisterServiceImp implements RegisterService {
Connection conn = null;
@Override
public void register(Account account) {
try {
conn = MySQLUtil.getConnection();
AccountDaoFactory.getAccountDaoInstance(conn).insertAccount(account);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
package com.wanbangee.servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.wanbangee.entities.Account;
import com.wanbangee.service.RegisterService;
import com.wanbangee.service.imp.RegisterServiceImp;
import com.wanbangee.util.NewFileName;
//多次提交不会重复提交,只会覆盖前面的内容
//每次改动程序,都会重新部署,原来上传的文件会消失
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
//注册信息提交,文件上传的步骤
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建磁盘工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.创建处理工具
ServletFileUpload upload = new ServletFileUpload(factory);
//3.设置上传文件的大小
upload.setFileSizeMax(1024*1024*5);//最大可上传5M内容
String accName = "";//用户名
String accPass = "";//用户密码
String accPic = "";//用户头像
try {//4.用集合接收表单提交的全部内容
List<FileItem> fileItems = upload.parseRequest(request);
//遍历循环集合,用增强for循环foreach
for (FileItem fileItem : fileItems) {
if(fileItem.isFormField()) {//不是文件
if(fileItem.getFieldName().equals("accName")) {
//如果传过来的是accName,则值就是accName
//accName = fileItem.getString();//获取accName的值
//accName = fileItem.getString();//用户名中文传到数据库会乱码马é¹é¹,密码是非中文的不用管
accName = new String(fileItem.getString().getBytes("ISO8859-1"),"utf-8");
//但数据库依然乱码???,这里能保证accName不乱码,
//是连接数据库时乱码,在连库URL后加上?useUnicode=true&characterEncoding=utf-8
}else if(fileItem.getFieldName().equals("accPass")) {
accPass = fileItem.getString();//获取accPass的值
}
}else {//是文件,就要保存文件
//首先要取得文件的各种信息,但是要给文件重命名
//获得文件名后缀suffix,fileItem.getName()获得文件名
//如取得abc.jpg,按照.来分割,用split(".")方法分割字符串,分割成数组的两个元素,
//fileItem.getName().split(".")分割后结果是个数组,有2个元素abc和jpg,
//split(".")分割方法是支持正则的方法,.在正则表达式里表示任意字符,即会将abc.jpg分割成7个字符
//加个斜杆split("\.")表示它就是一个点,斜杆\是转义字符不能写单个斜杆,必须写两个斜杆\\,split("\\.")
String suffix = fileItem.getName().split("\\.")[1];
//给文件accPic重命名,要求上传头像的文件命名为 客户端IP+时间戳+三位1-10之间随机数.后缀
//取得客户端ip要request对象才能获取,request.getRemoteAddr()
//在工具类util中写个静态方法取得客户端ip
accPic = NewFileName.getNewFileName(request)+"."+suffix;//新的文件名
//在根目录WebContent下new个pic目录用来存放上传的头像
//保存文件
InputStream in = fileItem.getInputStream();//取得文件输入流(字节输入流)
byte[] b = new byte[(int) fileItem.getSize()];//取得集合的字节长度是个long类型要强转为int
in.read(b);//将内容读取到字节数组中
//将字节数组写入到新的文件中,文件的路径是pic路径,pic+/+新的文件名,pic路径+File.separator+accPic
//取得项目虚拟目录真实路径(在硬盘中位置),this.getServletContext()获得application对象,application.getRealPath("/pic")取得硬盘中实际运行项目的地址
File file = new File(this.getServletContext().getRealPath("/pic")+File.separator+accPic);
OutputStream out = new FileOutputStream(file);
out.write(b);//将字节数组写入到流中,把这个流写入到这个文件
in.close();
out.close();
//控制层servlet调用业务层
//将注册的用户信息保存到账户表
RegisterService service = new RegisterServiceImp();
Account account = new Account();
account.setAccName(accName);
account.setAccPass(accPass);
account.setAccPic(accPic);
service.register(account);//传递的是account对象,得将上面那些信息封装成account对象
//注册成功后跳转到登入页面,重定向到/jsp/login.jsp中
response.sendRedirect(request.getContextPath()+"/jsp/login.jsp");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/loginServlet" method = "post">
用户名:<input type = "text" name = "username">
密码:<input type = "password" name = "password">
<input type = "submit" value = "登入">
<a href = "register.jsp">注册</a>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src = "${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName">
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
要求用户名和头像信息一起显示到在线用户列表
修改登录程序,和在线用户列表,要求将用户的头像信息也能够加入到session域中。
当初获取在线用户列表,在监听器OnLineListener.java中,将在线用户信息放到集合中List<Account> accounts,然后在books.jsp页面中获取。集合是从session域中取得的account对象放到List,session中取得的account对象就是登录时放到Account中的对象。
就是在account对象中加个acc_pic属性,即在accountDaoImp.java中查询sql加个acc_pic字段,
然后加入到account对象中account.setAccPic(res.getString("acc_pic"));
在books.jsp中在线用户列表加上头像信息
<h3>在线用户列表</h3>
<ul>
<!-- 循环在线用户的集合 -->
<c:forEach items="${onlines }" var="account">
<li>${account.accName }----><img src="${pageContext.request.contextPath }/pic/${account.accPic}" width="50px" height="50px"></li>
</c:forEach>
</ul>
用EL表达式做循环遍历集合元素,一定要导包和引入标签库
点击在线用户列表的头像就会下载头像
文件下载和FileUpload没关系。图片下载,将图片二进制字节响应给用户。设置响应头和下载路径。
在books.jsp中在线用户列表加上头像a标签下载
<h3>在线用户列表</h3>
<ul>
<!-- 循环在线用户的集合 -->
<c:forEach items="${onlines }" var="account">
<li>${account.accName }----><a href="${pageContext.request.contextPath }/DownPicServlet?fileName=${account.accPic}"><img src="${pageContext.request.contextPath }/pic/${account.accPic}" width="50px" height="50px"></a></li>
</c:forEach>
</ul>
new 个Servlet命名为DownPicServlet用来做图片的下载操作
package com.wanbangee.servlet;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//图片下载,将图片二进制字节响应给用户
//设置响应头和下载路径
@WebServlet("/DownPicServlet")
public class DownPicServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//取得超链接用地址栏传递过来得参数fileName
String fileName = request.getParameter("fileName");
//获得文件的真实路径
File file = new File(this.getServletContext().getRealPath("/pic")+File.separator+fileName);
//获得文件字节输入流
InputStream in = new FileInputStream(file);
//这里是file对象,和RegisterServlet.java中fileItem对象不一样的
byte[] b = new byte[(int) file.length()];
//将文件内容写到字节数组中,就是一个二进制字节数组
in.read(b);
//设置MIME类型,表示是一个文件或二进制流
response.setContentType("application/octet-stream");
//不再是以text/html形式了,而是以流的形式进行响应
//设置响应头(设置为文件下载的形式)
response.addHeader("Content-Disposition", "attachment;filename="+fileName);
//文件下载的形式,以这个文件名fileName下载
//只要将字节数组响应给浏览器就行
// PrintWriter out = response.getWriter(); //字符打印流,不能响应字节,Writer是字符输出流,响应的得是字节
// out.print(b);//打印的是一个字符
//向浏览器输出字节数组,一行行输出,但是还不能下载,必须设置MIME类型和响应头
//要想输出字节得用OutputStream或者PrintStream
OutputStream out = response.getOutputStream();//这才是字节输出流
in.close();//关闭字节输入流
out.write(b);//输出的是字节
out.close();
//下载是将文件的二进制字节响应给用户,文件下载和FileUpload组件没有关系
//断点只能在java程序中
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
//jsp访问和目录有关,映射地址和在哪个目录下无关
Ajax简介
Ajax: Asynchronous JavaScript and xml,叫做异步执行JavaScript和xml,
Ajax并不是一个新的技术,在Ajax这个名字出来之前,叫做局部页面刷新技术,我们之前写过的代码,比如买书程序,
每当向服务器发送一个请求,哪怕只是一点点的局部的内容,都会将整个页面进行刷新,既然是刷新整个页面的话,
那么肯定会重新加载页面的所有内容,导致程序执行效率下降,而如果使用了Ajax之后,就可以实现局部的页面刷新,
不需要再将整个页面刷新,性能显然会比之前好很多。
Ajax主要使用XMLHttpRequest这个对象发送异步请求和响应处理,这个对象也称为Ajax的核心对象,但是这个对象有很大的问题,就是不同的内核的浏览器此对象获取方式不同,也就说兼容性不高。我们目前只关注火狐或者谷歌,IE不管,
IE浏览器执行原生的ajax是有问题的。IE浏览器兼容能执行jQuery封装的ajax
在我们开发中实际上就是可以并发执行JavaScript和Servlet 程序,我们之前所编写所有的jsp和Servlet 程序,
实际上在某一个时间点上,要么只执行Jsp,要么只执行Servlet(后端),两者不能够同时执行,
这样实际上就浪费系统的资源,而且降低了执行的效率。使用了Ajax之后,我们就可以更加高效,快捷的处理器请求。
原生ajax异步请求
用ajax请求来验证,注册时用户名不能重复。
ajax跳转时地址栏没有发送改变,是个转发操作。
每次都去执行servlet,service,dao来判断用户名是否存在。
从用户感觉上没执行servlet,前后端异步执行了。
Ajax异步请求的步骤:
1.创建XMLHttpRequest对象
2.调用XMLHttpRequest对象的open函数创建提交路径,提交路径为一个Servlet的URL映射地址
3.为XMLHttpRequest对象设置状态改变事件(设置回调函数)
4.调用XMLHttpRequest对象的send函数进行提交
5.获取Servelt响应结果
new个servlet命名为RegisterCheckServlet
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.service.RegisterService;
import com.wanbangee.service.imp.RegisterServiceImp;
@WebServlet("/RegisterCheckServlet")
public class RegisterCheckServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//ajax提交到servlet,此时ajax状态为2,状态值为2:表示Ajax核心对象已经提交到了Servlet
response.setCharacterEncoding("utf-8");//设置响应内容得字符集,不加的话显示的信息会乱码
response.setContentType("text/html;charset=uft-8");//设置响应内容的MIME类型
//获得out对象,servlet中把内容响应到页面用out.print()一行行输出
PrintWriter out = response.getWriter();
//如果把内容放到请求域request.setAttribute;放到session就是session.setAttribute
//取得请求参数
String accName = request.getParameter("accName");
//获得了用户名就可以去数据库进行校验,用户名在数据库存在就不让注册
//调用业务层
RegisterService service = new RegisterServiceImp();
boolean flag = service.checkAccName(accName);
out.print(flag);//将flag响应给前端,前端接收到flag为true表示用户名可用
//out.println(false);//开始响应内容给页面,这时ajax状态为3,状态值为3:表示Servlet已经开始响应内容了
//out.println("666");//print加ln表示换行输出,可以多次响应信息
out.close();
//响应结束,ajax状态为4,状态值为4:表示Servelt响应信息结束
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
在AccountDao加个用户名查询判断:
//根据用户名查询数据笔数,查询为0笔数据说明没有这个用户名,查询为1笔说明这个用户名已经存在
public int selectCountByAccName(String accName);
在AccountDaoImp复写此方法:
@Override
public int selectCountByAccName(String accName) {
int count = 0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select count(*) from account where acc_name = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, accName);
res = pstate.executeQuery();
while(res.next()) {
count = res.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return count;
}
在业务层RegisterService加个验证用户名是否可用的业务:
//验证用户名是否可用
public boolean checkAccName(String accName);
在RegisterServiceImp复写此方法:
@Override
public boolean checkAccName(String accName) {
boolean flag =false;
Connection conn = null;
try {
conn = MySQLUtil.getConnection();
int count = AccountDaoFactory.getAccountDaoInstance(conn).selectCountByAccName(accName);
if(count == 0) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
在register.jsp页面展现出来,获取servlet响应的信息。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src = "${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
//做ajax异步请求
var xmlhttp = new XMLHttpRequest();//创建ajax核心对象
var accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
if(!accNameCheck){ //accNameCheck响应的信息控制表单能否提交的问题
alert("用户名不可用"); //true才执行if,false进不来if
return false;
}
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
//给这个用户名一个失去焦点的事件(blur)
$("#accName").blur(function(){
//alert(123);
var accName = $(this).val();
//alert(accName);
xmlhttp.onreadystatechange = ajaxback;//设置ajax核心对象状态改变事件
xmlhttp.open("get","${pageContext.request.contextPath}/RegisterCheckServlet?accName="+accName);//设置异步请求地址
//随便用哪种请求方式,在js中用EL表达式
/*ajax核心对象状态有四种:
状态值为1 : 表示Ajax核心对象已经设置了提交的路径
状态值为2: 表示Ajax核心对象已经提交到了Servlet
状态值为3 : 表示Servlet已经开始响应内容了
状态值为4 : 表示Servelt响应信息结束 */
xmlhttp.send(null);//ajax提交到Servlet
});
function ajaxback(){
//状态改变,执行这个ajaxback事件
//等Servlet响应信息结束,才获取响应的内容,当ajax状态为4时,获取响应的内容
//alert(xmlhttp.readyState);//状态1,2,3,4弹出来没有意义
if(xmlhttp.readyState == 4){//servlet已经响应内容结束了
//获得响应内容
var responseContent = xmlhttp.responseText;//获得servlet响应的内容
//alert(responseContent);
//servlet响应什么信息能在jsp获取到就行
if(responseContent == "true" || responseContent == true){
$("#checkMessage").html("<font style = 'color:green'>用户名可用</font>");
accNameCheck = true;//accNameCheck响应的信息控制表单能否提交的问题
}else{
$("#checkMessage").html("<font style = 'color:red'>用户名不可用</font>");
accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
}
}
}
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName"><span id = "checkMessage"></span>
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
jQuery完成异步请求
jQuery对原生js进行了封装,提供一套函数库,也对原生Ajax异步请求进行了封装,使得异步请求更加简单。
通过jQuery帮助手册查看jQuery封装的异步请求的函数(常用的三个函数):
$.ajax(url,[settings]) : 常用,发送请求,[settings]可以设置为get请求或者post请求
$.get(url,[data],[fn],[type]) : 常用,发送get请求
$.post(url,[data],[fn],[type]) : 常用,发送post请求
语法一:$.ajax(url,[settings]) , 通常设置请求类型,参数,请求地址,成功回调函数,失败回调函数等
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src = "${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
var accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
if(!accNameCheck){ //accNameCheck响应的信息控制表单能否提交的问题
alert("用户名不可用"); //true才执行if,false进不来if
return false;
}
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
//给这个用户名一个失去焦点的事件(blur)
$("#accName").blur(function(){
var accName = $(this).val();
var param = {
accName : accName //js中对象的写法
};
$.ajax({
type:"post",//请求方式
url:"${pageContext.request.contextPath}/RegisterCheckServlet",//请求地址
data:param,//请求参数
success:function(data){ //表示请求成功的回调函数,data表示接收到的响应内容
if(data == "true" || data == true){
$("#checkMessage").html("<font style = 'color:green'>用户名可用</font>");
accNameCheck = true;//accNameCheck响应的信息控制表单能否提交的问题
}else{
$("#checkMessage").html("<font style = 'color:red'>用户名不可用</font>");
accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
}
},
error:function(data){ //表示请求失败的回调函数,data表示接收到的响应内容
}
});
});
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName"><span id = "checkMessage"></span>
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
语法二:$.get(url,[data],[fn],[type]) 简单的get请求
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src = "${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
var accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
if(!accNameCheck){ //accNameCheck响应的信息控制表单能否提交的问题
alert("用户名不可用"); //true才执行if,false进不来if
return false;
}
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
//给这个用户名一个失去焦点的事件(blur)
$("#accName").blur(function(){
var accName = $(this).val();
var param = {
accName : accName //js中对象的写法
};
var url = "${pageContext.request.contextPath}/RegisterCheckServlet";
$.get(url,param,function(data){//参数3响应完成后的回调函数,data表示接收到的响应内容
if(data == "true" || data == true){
$("#checkMessage").html("<font style = 'color:green'>用户名可用</font>");
accNameCheck = true;//accNameCheck响应的信息控制表单能否提交的问题
}else{
$("#checkMessage").html("<font style = 'color:red'>用户名不可用</font>");
accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
}
});
});
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName"><span id = "checkMessage"></span>
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
语法三:$.post(url,[data],[fn],[type]) 简单的post请求
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src = "${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
var accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
if(!accNameCheck){ //accNameCheck响应的信息控制表单能否提交的问题
alert("用户名不可用"); //true才执行if,false进不来if
return false;
}
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
//给这个用户名一个失去焦点的事件(blur)
$("#accName").blur(function(){
var accName = $(this).val();
var param = {
accName : accName //js中对象的写法
};
var url = "${pageContext.request.contextPath}/RegisterCheckServlet";
$.post(url,param,function(data){//参数3响应完成后的回调函数,data表示接收到的响应内容
if(data == "true" || data == true){
$("#checkMessage").html("<font style = 'color:green'>用户名可用</font>");
accNameCheck = true;//accNameCheck响应的信息控制表单能否提交的问题
}else{
$("#checkMessage").html("<font style = 'color:red'>用户名不可用</font>");
accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
}
});
});
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName"><span id = "checkMessage"></span>
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>
JSON数据交互
前后端的异步请求,数据交互往往不是简单的String,boolean等简单类型,
而往往是Map,List,Object(数组,集合,对象)等,这种格式的数据在前端如何解析呢?
为了便于JavaScript解析数据,我们使用JSON格式,步骤如下:
- 导这6个包
commons-beanutils-1.7.0.jar
commons-collections-3.2.jar
commons-lang-2.4.jar
commons-logging-1.1.jar
ezmorph-1.0.4.jar
json-lib-2.2.2-jdk15.jar
编写Servlet,new个Servlet命名为TestJsonDataServlet
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.entities.BookInfo;
import com.wanbangee.service.BookService;
import com.wanbangee.service.imp.BookServiceImp;
import net.sf.json.JSONArray;
//Json数据交互,复杂数据类型像数组,对象,集合等,要用json数据格式
@WebServlet("/TestJsonDataServlet")
public class TestJsonDataServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");//设置响应内容得字符集,不加的话显示的信息会乱码
response.setContentType("text/html;charset=uft-8");//设置响应内容的MIME类型
//查询图书信息,将图书信息加入到请求域中
BookService bookService = new BookServiceImp();
List<BookInfo> bookInfos = bookService.selectBookInfo();
//Map<String,Object> map = new HashMap<>();
//map.put("books", bookInfos); //响应Map键值对给前端
//map.put("name", "姜建民");
//map.put("total", 2);
//获得out对象,servlet中把内容响应到页面用out.print()一行行输出
PrintWriter out = response.getWriter();
//响应的内容不再是普通的格式,而是JSON数据格式
JSONArray jsonArray = new JSONArray();//实例化JSONArray对象jsonArray
jsonArray.addAll(bookInfos);//将集合添加到jsonArray中
//jsonArray.element(map);//现在响应的是map键值对
out.print(jsonArray);//响应jsonArray给前端
//out.print(bookInfos);直接响应集合给前端,控制台会收到下面内容,这样的内容js无法解析
//[com.wanbangee.entities.BookInfo@9665b69, com.wanbangee.entities.BookInfo@4e50e443]
//这样的内容js无法解析,这个时候就该用json数据格式
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
编写JSP发送异步请求
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){
var url = "${pageContext.request.contextPath}/TestJsonDataServlet";
//参数是空的可以不写 var param = {}; $.post(url,param,function(data){
$.post(url,function(data){//参数为空可以省略
data = eval(data);//解析字符串为JSON格式
console.log(data);
var content = "";
for (var i = 0; i < data.length; i++) {
//创建一个组件,这种写法很麻烦,没有拼接方便
//var tr = document.createElement("tr");
/* console.log(data[i].name);
console.log(data[i].total); //响应Map键值对给前端
console.log(data[i].books); */
content += "<tr>"
content += "<td>"+ data[i].bookNo +"</td>"
content += "<td>"+ data[i].bookName +"</td>"
content += "<td>"+ data[i].bookPrice +"</td>"
content += "<td>"+ data[i].bookStock.stockNum +"</td>"
content += "</tr>"
}
//数据遍历后放到下面的showBook表格中
$("#showBook").html(content);//把js中数据放到html中
//java程序在服务器运行,造成服务器压力大,js代码在浏览器执行
//这种写法能降低服务器压力,提高服务器效率,提升服务器性能
});
});
</script>
</head>
<body><!-- 把数据渲染到表格中 -->
<table border = "1">
<caption>图书信息表</caption>
<thead>
<tr>
<td>图书号</td>
<td>图书名</td>
<td>图书单价</td>
<td>图书库存</td>
</tr>
</thead>
<tbody id="showBook">
</tbody>
</table>
</body>
</html>
总结:
1. 在以后的开发中,不会再使用表单提交,或者超链接等形式直接访问后端,而全使用Ajax异步请求
2. 原生的Ajax异步请求比较麻烦,以后都使用jQuery封装好的请求处理。
3. 异步请求的数据交互一定是使用JSON格式,不仅仅是JavaScript中,
包括Android,IOS端,各种小程序都是发送异步请求,获得JSON数据。
终极项目练习
将登录,注册,图书信息显示,买书程序完成编写,要求
- 所有的请求都是用异步请求
- 图书信息展示,要求分页显示图书信息
package com.wanbangee.util;
import java.sql.Connection;
import java.sql.DriverManager;
public class MYSQLUtil {
public final static String DRIVER = "com.mysql.jdbc.Driver";
public final static String URL = "jdbc:mysql://127.0.0.1:3306/buybook";
public final static String USER = "root";
public final static String PASSWORD = "3306";
public static Connection getConnection() throws Exception {
Connection conn = null;
//2 加载驱动程序[实现了JDBC标准接口的MySQL实现程序]
Class.forName(DRIVER);
//3取得数据库连接
conn = DriverManager.getConnection(URL, USER, PASSWORD);
return conn;
}
}
//为上传的文件重命名
package com.wanbangee.util;
import javax.servlet.http.HttpServletRequest;
public class NewFileName {
public static String getNewFileName(HttpServletRequest request) {
StringBuffer sb = new StringBuffer();
// IPV6 地址是以冒号分割,IPV4以.分割
String remoteAddr = request.getRemoteAddr().replaceAll(":", "").replaceAll("\\.", "");
sb.append(remoteAddr);
Long currentTime = System.currentTimeMillis();//取得时间戳
sb.append(currentTime);
//三位随机数
for(int i = 0;i<3;i++) {
int random = (int) Math.round(Math.random()*9);
sb.append(random);
}
return sb.toString();
}
}
package com.wanbangee.entities;
public class Account {
private Integer accId;
private String accName;
private String accPass;
private Double accBalance;
private String accPic;
public String getAccPic() {
return accPic;
}
public void setAccPic(String accPic) {
this.accPic = accPic;
}
public Integer getAccId() {
return accId;
}
public void setAccId(Integer accId) {
this.accId = accId;
}
public String getAccName() {
return accName;
}
public void setAccName(String accName) {
this.accName = accName;
}
public String getAccPass() {
return accPass;
}
public void setAccPass(String accPass) {
this.accPass = accPass;
}
public Double getAccBalance() {
return accBalance;
}
public void setAccBalance(Double accBalance) {
this.accBalance = accBalance;
}
public Account() {
}
public Account(Integer accId, String accName, String accPass, Double accBalance, String accPic) {
super();
this.accId = accId;
this.accName = accName;
this.accPass = accPass;
this.accBalance = accBalance;
this.accPic = accPic;
}
}
package com.wanbangee.entities;
public class BookInfo {
private Integer bookNo;
private String bookName;
private Double bookPrice;
private Integer stockId;
private BookStock bookStock;
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public Double getBookPrice() {
return bookPrice;
}
public void setBookPrice(Double bookPrice) {
this.bookPrice = bookPrice;
}
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public BookStock getBookStock() {
return bookStock;
}
public void setBookStock(BookStock bookStock) {
this.bookStock = bookStock;
}
public BookInfo(Integer bookNo, String bookName, Double bookPrice, Integer stockId) {
super();
this.bookNo = bookNo;
this.bookName = bookName;
this.bookPrice = bookPrice;
this.stockId = stockId;
}
public BookInfo() {
super();
}
}
package com.wanbangee.entities;
public class BookStock {
private Integer stockId;
private Integer bookNo;
private Integer stockNum;
public Integer getStockId() {
return stockId;
}
public void setStockId(Integer stockId) {
this.stockId = stockId;
}
public Integer getBookNo() {
return bookNo;
}
public void setBookNo(Integer bookNo) {
this.bookNo = bookNo;
}
public Integer getStockNum() {
return stockNum;
}
public void setStockNum(Integer stockNum) {
this.stockNum = stockNum;
}
public BookStock(Integer stockId, Integer bookNo, Integer stockNum) {
super();
this.stockId = stockId;
this.bookNo = bookNo;
this.stockNum = stockNum;
}
public BookStock() {
super();
}
}
package com.wanbangee.dao;
import com.wanbangee.entities.Account;
public interface AccountDao {
//根据用户名和密码查询用户信息
public Account selectAccountByAccNameAndAccPass(String accName,String accPass);
//新增用户信息操作
public void insertAccount(Account account);
//根据用户名查询数据笔数
public int selectCountByAccName(String accName);
//修改账户余额
public void updateAccBalanceByAccId(Integer accId,Double bookPrice);
//查询账户余额
public Double selectAccBalanceByAccId(Integer accId);
}
package com.wanbangee.dao;
import java.util.List;
import com.wanbangee.entities.BookInfo;
public interface BookInfoDao {
//查询所有的图书信息,模糊查询和分页查询
/*@param pageSize 每页显示的数据笔数
* @param pageCurrent 当前显示第几页*/
public List<BookInfo> selectBookInfo(String bookName,Integer pageSize,Integer pageCurrent);
//查询数据笔数
public int selectCountByBookName(String bookName);
//查询图书单价
public Double selectBookPriceByBookNo(Integer bookNo);
}
package com.wanbangee.dao;
import com.wanbangee.entities.BookStock;
public interface BookStockDao {
//根据库存ID查询图书的库存信息
public BookStock selectStockInfoByStockId(Integer stockId);
//减少库存
public void updateStockNumByBookNo(Integer bookNo,Integer buyNum);
//查询图书库存
public Integer selectStockNumByBookNo(Integer bookNo);
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.entities.Account;
public class AccountDaoImp implements AccountDao {
private Connection conn;
public AccountDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public Account selectAccountByAccNameAndAccPass(String accName, String accPass) {
Account account = null;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select acc_id,acc_balance,acc_pic from account where acc_name = ? and acc_pass = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, accName);
pstate.setString(2, accPass);
res = pstate.executeQuery();
while(res.next()) {
account = new Account();
account.setAccName(accName);
account.setAccId(res.getInt(1));
account.setAccBalance(res.getDouble(2));
account.setAccPic(res.getString(3));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return account;
}
@Override
public void insertAccount(Account account) {
PreparedStatement pstate = null;
try {
String sql = "insert into account (acc_name,acc_pass,acc_pic) values (?,?,?)";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, account.getAccName());
pstate.setString(2, account.getAccPass());
pstate.setString(3, account.getAccPic());
pstate.execute();
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public int selectCountByAccName(String accName) {
int count = 0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql ="select count(*) from account where acc_name = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, accName);
res = pstate.executeQuery();
while(res.next()) {
count = res.getInt(1);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return count;
}
@Override
public void updateAccBalanceByAccId(Integer accId, Double bookPrice) {
PreparedStatement pstate = null;
try {
String sql = "update account set acc_balance = acc_balance + ? where acc_id = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setDouble(1, bookPrice);
pstate.setInt(2, accId);
pstate.execute();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
@Override
public Double selectAccBalanceByAccId(Integer accId) {
Double accBalance = 0.0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select acc_balance from account where acc_id = ? ";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, accId);
res = pstate.executeQuery();
while(res.next()) {
accBalance = res.getDouble(1);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return accBalance;
}
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.entities.BookInfo;
public class BookInfoDaoImp implements BookInfoDao {
private Connection conn;
public BookInfoDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public List<BookInfo> selectBookInfo(String bookName,Integer pageSize,Integer pageCurrent) {
List<BookInfo> bookInfos = new ArrayList<>();
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql ="select book_no,book_name,book_price,stock_id from book_info where book_name like ? limit ?,?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1,"%"+bookName+"%");
pstate.setInt(2, (pageCurrent-1) * pageSize );
pstate.setInt(3,pageSize );
res = pstate.executeQuery();
while(res.next()) {//Integer bookNo, String bookName, Double bookPrice, Integer stockId
BookInfo bookInfo = new BookInfo(res.getInt(1), res.getString(2), res.getDouble(3), res.getInt(4));
bookInfos.add(bookInfo);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return bookInfos;
}
@Override
public int selectCountByBookName(String bookName) {
int count = 0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select count(*) from book_info where book_name like ?";
pstate = this.conn.prepareStatement(sql);
pstate.setString(1, "%"+bookName+"%");
res = pstate.executeQuery();
while(res.next()) {
count = res.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return count;
}
@Override
public Double selectBookPriceByBookNo(Integer bookNo) {
Double bookPrice = 0.0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select book_price from book_info where book_no = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, bookNo);
res = pstate.executeQuery();
while(res.next()) {
bookPrice = res.getDouble(1);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return bookPrice;
}
}
package com.wanbangee.dao.imp;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.entities.Account;
import com.wanbangee.entities.BookStock;
public class BookStockDaoImp implements BookStockDao {
private Connection conn;
public BookStockDaoImp(Connection conn) {
this.conn = conn;
}
@Override
public BookStock selectStockInfoByStockId(Integer stockId) {
BookStock bookStock = null;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select book_no,stock_num from book_stock where stock_id = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, stockId);
res = pstate.executeQuery();
while(res.next()) {
//Integer stockId, Integer bookNo, Integer stockNum
bookStock = new BookStock(stockId,res.getInt(1),res.getInt(2));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return bookStock;
}
@Override
public void updateStockNumByBookNo(Integer bookNo, Integer buyNum) {
PreparedStatement pstate = null;
try {
String sql = "update book_stock set stock_num = stock_num+? where book_no = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, buyNum);
pstate.setInt(2, bookNo);
pstate.execute();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
pstate.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
@Override
public Integer selectStockNumByBookNo(Integer bookNo) {
Integer stockNum = 0;
PreparedStatement pstate = null;
ResultSet res = null;
try {
String sql = "select stock_num from book_stock where book_no = ?";
pstate = this.conn.prepareStatement(sql);
pstate.setInt(1, bookNo);
res = pstate.executeQuery();
while(res.next()) {
stockNum = res.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
res.close();
pstate.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return stockNum;
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.AccountDao;
import com.wanbangee.dao.imp.AccountDaoImp;
public class AccountDaoFactory {
public static AccountDao getAccountDaoInstance(Connection conn) {
return new AccountDaoImp(conn);
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.BookInfoDao;
import com.wanbangee.dao.imp.BookInfoDaoImp;
public class BookInfoDaoFactory {
public static BookInfoDao getBookInfoDaoInstance(Connection conn) {
return new BookInfoDaoImp(conn);
}
}
package com.wanbangee.dao.factory;
import java.sql.Connection;
import com.wanbangee.dao.BookStockDao;
import com.wanbangee.dao.imp.BookStockDaoImp;
public class BookStockDaoFactory {
public static BookStockDao getBookStockDaoInstance(Connection conn) {
return new BookStockDaoImp(conn);
}
}
过滤器
package com.wanbangee.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
//过滤器,设置请求的统一编码
@WebFilter("/*")
public class CharSetFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");//设置请求的统一编码
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
package com.wanbangee.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
//过滤所有请求地址,把不需要过滤的写进if条件中
@WebFilter("/*") //过滤非法用户
public class LoginFiter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
String path = req.getContextPath();
String URI = req.getRequestURI();
HttpSession session = req.getSession();
if(null != session.getAttribute("account")
|| URI.indexOf("login.jsp") != -1
|| URI.indexOf("LoginServlet") != -1
|| URI.indexOf("register.jsp") != -1
|| URI.indexOf("RegisterCheckServlet") != -1
|| URI.indexOf("RegisterServlet") != -1
|| URI.indexOf("jquery-1.10.1.js") != -1) {
chain.doFilter(request, response);
}else {
res.sendRedirect(path + "/jsp/login.jsp");
}
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
package com.wanbangee.service;
import java.util.List;
import com.wanbangee.entities.BookInfo;
public interface BookService {
//模糊查询
public List<BookInfo> selectBookInfoLikeBookName(String bookName,Integer pageSize,Integer pageCurrent);
//查询数据笔数
public int selectCountByBookName(String bookName);
/**
* 买书
* @param accId
* @param bookNo
* return
* 1 表示买书成功
* 2 表示账户余额不足
* 3 表示图书库存不足
*/
public int buyBook(Integer accId,Integer bookNo);
/**
* 买多本
* @param accId
* @param bookNos
* return
* 1 表示买书成功
* 2 表示账户余额不足
* 3 表示图书库存不足
*/
public int buyBooks(Integer accId,String bookNos);
}
package com.wanbangee.service;
import com.wanbangee.entities.Account;
public interface LoginService {
public Account login(String accName,String accPass);
}
package com.wanbangee.service;
import com.wanbangee.entities.Account;
public interface RegisterService {
//注册业务
public void register(Account account);
//验证用户名是否可用
public boolean checkAccName(String accName);
}
package com.wanbangee.service.imp;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import com.wanbangee.dao.factory.AccountDaoFactory;
import com.wanbangee.dao.factory.BookInfoDaoFactory;
import com.wanbangee.dao.factory.BookStockDaoFactory;
import com.wanbangee.entities.BookInfo;
import com.wanbangee.service.BookService;
import com.wanbangee.util.MYSQLUtil;
public class BookServiceImp implements BookService {
@Override
public List<BookInfo> selectBookInfoLikeBookName(String bookName,Integer pageSize,Integer pageCurrent) {
Connection conn = null;
List<BookInfo> bookInfos = null;
try {
conn = MYSQLUtil.getConnection();
bookInfos = BookInfoDaoFactory.getBookInfoDaoInstance(conn).selectBookInfo(bookName,pageSize,pageCurrent);
for (BookInfo bookInfo : bookInfos) {
bookInfo.setBookStock(BookStockDaoFactory.getBookStockDaoInstance(conn).selectStockInfoByStockId(bookInfo.getStockId()));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return bookInfos;
}
@Override
public int selectCountByBookName(String bookName) {
int count = 0;
Connection conn = null;
try {
conn = MYSQLUtil.getConnection();
count = BookInfoDaoFactory.getBookInfoDaoInstance(conn).selectCountByBookName(bookName);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return count;
}
@Override
public int buyBook(Integer accId, Integer bookNo) {
int flag = 1;
Connection conn = null;
try {
conn = MYSQLUtil.getConnection();
conn.setAutoCommit(false);//取消事务的自动提交
//1查询图书单价
Double bookPrice = BookInfoDaoFactory.getBookInfoDaoInstance(conn).selectBookPriceByBookNo(bookNo);
//2 减少图书库存
BookStockDaoFactory.getBookStockDaoInstance(conn).updateStockNumByBookNo(bookNo, -1);
//2.1 查询图书库存
Integer stockNum = BookStockDaoFactory.getBookStockDaoInstance(conn).selectStockNumByBookNo(bookNo);
if(stockNum < 0) {
flag = 3;
throw new RuntimeException("图书库存不足");
}
//3 减少账户余额
AccountDaoFactory.getAccountDaoInstance(conn).updateAccBalanceByAccId(accId, bookPrice*(-1));
//3.1查询账户余额
Double accBalance = AccountDaoFactory.getAccountDaoInstance(conn).selectAccBalanceByAccId(accId);
if(accBalance < 0) {
flag = 2;
throw new RuntimeException("账户余额不足");
}
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (Exception e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return flag;
}
@Override
public int buyBooks(Integer accId, String bookNos) {
int flag = 1;
String bookNoStrs[] = bookNos.split(",");
Connection conn = null;
try {
conn = MYSQLUtil.getConnection();
conn.setAutoCommit(false);//取消事务的自动提交
for (String bookNoStr : bookNoStrs) {
//1查询图书单价
Double bookPrice = BookInfoDaoFactory.getBookInfoDaoInstance(conn).selectBookPriceByBookNo(Integer.parseInt(bookNoStr));
//2 较少图书库存
BookStockDaoFactory.getBookStockDaoInstance(conn).updateStockNumByBookNo(Integer.parseInt(bookNoStr), -1);
//2.1 查询图书库存
Integer stockNum = BookStockDaoFactory.getBookStockDaoInstance(conn).selectStockNumByBookNo(Integer.parseInt(bookNoStr));
if(stockNum < 0) {
flag = 3;
throw new RuntimeException("图书库存不足");
}
//3 减少账户余额
AccountDaoFactory.getAccountDaoInstance(conn).updateAccBalanceByAccId(accId, bookPrice*(-1));
//3.1查询账户余额
Double accBalance = AccountDaoFactory.getAccountDaoInstance(conn).selectAccBalanceByAccId(accId);
if(accBalance < 0) {
flag = 2;
throw new RuntimeException("账户余额不足");
}
}
conn.commit();
} catch (Exception e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return flag;
}
}
package com.wanbangee.service.imp;
import java.sql.Connection;
import com.wanbangee.dao.factory.AccountDaoFactory;
import com.wanbangee.entities.Account;
import com.wanbangee.service.LoginService;
import com.wanbangee.util.MYSQLUtil;
public class LoginServiceImp implements LoginService {
@Override
public Account login(String accName, String accPass) {
Connection conn = null;
Account account = null;
try {
conn = MYSQLUtil.getConnection();
account = AccountDaoFactory.getAccountDaoInstance(conn).selectAccountByAccNameAndAccPass(accName, accPass);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return account;
}
}
package com.wanbangee.service.imp;
import java.sql.Connection;
import com.wanbangee.dao.factory.AccountDaoFactory;
import com.wanbangee.entities.Account;
import com.wanbangee.service.RegisterService;
import com.wanbangee.util.MYSQLUtil;
public class RegisterServiceImp implements RegisterService {
@Override
public void register(Account account) {
Connection conn = null;
try {
conn = MYSQLUtil.getConnection();
AccountDaoFactory.getAccountDaoInstance(conn).insertAccount(account);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
@Override
public boolean checkAccName(String accName) {
Connection conn = null;
boolean flag = false;
try {
conn = MYSQLUtil.getConnection();
int count = AccountDaoFactory.getAccountDaoInstance(conn).selectCountByAccName(accName);
if(count == 0) {
flag = true;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
conn.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
return flag;
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.entities.BookInfo;
import com.wanbangee.service.BookService;
import com.wanbangee.service.imp.BookServiceImp;
import net.sf.json.JSONArray;
@WebServlet("/BookServlet")
public class BookServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("UTF-8");//设置响应内容的字符集
response.setContentType("text/html;charset=utf-8");//设置响应内容的MIME类型
//获得out对象
PrintWriter out = response.getWriter();
//取得请求参数
String bookName = request.getParameter("bookName");
Integer pageSize = Integer.parseInt(request.getParameter("pageSize"));
Integer pageCurrent = Integer.parseInt(request.getParameter("pageCurrent"));
//调用业务层
BookService bookService = new BookServiceImp();
List<BookInfo> bookInfos = bookService.selectBookInfoLikeBookName(bookName,pageSize, pageCurrent);
int count = bookService.selectCountByBookName(bookName);//查询数据笔数
Map<String,Object> map = new HashMap<>();
if(bookInfos == null || bookInfos.isEmpty()) {
map.put("code", "102");
map.put("message", "查询失败");
}else {
map.put("code", 1001);
map.put("message", "查询成功");
map.put("bookInfos", bookInfos);//把查询结果集响应给前端
map.put("total", count);//把查询数据笔数响应给前端
}
JSONArray jsonArray = new JSONArray();
jsonArray.element(map);
out.print(jsonArray);
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.service.BookService;
import com.wanbangee.service.imp.BookServiceImp;
import net.sf.json.JSONArray;
@WebServlet("/BuyBookServlet")
public class BuyBookServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Integer bookNo = Integer.parseInt(request.getParameter("bookNo"));
Integer accId = Integer.parseInt(request.getParameter("accId"));
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
BookService service = new BookServiceImp();
int flag = service.buyBook(accId, bookNo);
Map<String,Object> map = new HashMap<>();
if(flag == 1) {
map.put("code", 1001);
map.put("message", "买书成功");
}else if(flag == 2) {
map.put("code", 1002);
map.put("message", "买书失败,账户余额不足");
}else if(flag == 3) {
map.put("code", 1002);
map.put("message", "买书失败,图书库存不足");
}
JSONArray json = new JSONArray();
json.element(map);
out.print(json);;
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.service.BookService;
import com.wanbangee.service.imp.BookServiceImp;
import net.sf.json.JSONArray;
@WebServlet("/BuyBooksServlet")
public class BuyBooksServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String bookNos = request.getParameter("bookNos");
Integer accId = Integer.parseInt(request.getParameter("accId"));
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
BookService service = new BookServiceImp();
int flag = service.buyBooks(accId, bookNos);
Map<String,Object> map = new HashMap<>();
if(flag == 1) {
map.put("code", 1001);
map.put("message", "买书成功");
}else if(flag == 2) {
map.put("code", 1002);
map.put("message", "买书失败,账户余额不足");
}else if(flag == 3) {
map.put("code", 1002);
map.put("message", "买书失败,图书库存不足");
}
JSONArray json = new JSONArray();
json.element(map);
out.print(json);;
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.wanbangee.entities.Account;
import com.wanbangee.service.LoginService;
import com.wanbangee.service.imp.LoginServiceImp;
import net.sf.json.JSONArray;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");//通过参数名取得值,取得的是字符串
String password = request.getParameter("password");//这个参数名是jsp页面中控件的name给开发人员看的
//控制层调用业务层
LoginService loginService = new LoginServiceImp();
Account account = loginService.login(username, password);
response.setCharacterEncoding("utf-8");
//获得out对象,servlet中把内容响应到页面用out.print()一行行输出
PrintWriter out = response.getWriter();
Map<String,Object> map = new HashMap<>();
//map对象存放返回前端的消息
if(account != null) {
//登录成功,将用户信息设置到session域中
HttpSession session = request.getSession(true);
session.setAttribute("account", account);
map.put("code", 1001);//map对象的两个属性code和message
map.put("message", "登录成功");
}else {
map.put("code", 1002);
map.put("message", "登录失败,用户名或密码输入错误");
}
//把map信息响应给前端
JSONArray jsonArray = new JSONArray();
jsonArray.element(map);//把一个map对象放进jsonArray
out.print(jsonArray);//把jsonArray打印到前端页面
out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.wanbangee.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wanbangee.service.RegisterService;
import com.wanbangee.service.imp.RegisterServiceImp;
@WebServlet("/RegisterCheckServlet")
public class RegisterCheckServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//ajax提交到servlet,此时ajax状态为2
response.setCharacterEncoding("utf-8");//设置响应内容得字符集
response.setContentType("text/html;charset=utf-8");//设置响应内容的MIME类型
//获得out对象,servlet响应内容用out一行行输出
PrintWriter out = response.getWriter();
//servlet中把内容响应到页面用out.print()
//如果把内容放到请求域request.setAttribute(name, o);放到session就是session.setAttribute
//取得请求参数
String accName = request.getParameter("accName");
//获得了用户名就可以去数据库进行校验,用户名在数据库存在就不让注册
//调用业务层
RegisterService service = new RegisterServiceImp();
boolean flag = service.checkAccName(accName);
out.print(flag);//将flag响应给前端,前端接收到为true表示用户名可用
//out.println(false);//开始响应内容给页面,这时ajax状态为3
//out.println("666");//可以多次响应,这时ajax状态为3
out.close();//响应结束,ajax状态为4
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
package com.wanbangee.servlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.wanbangee.entities.Account;
import com.wanbangee.service.RegisterService;
import com.wanbangee.service.imp.RegisterServiceImp;
import com.wanbangee.util.NewFileName;
@WebServlet("/RegisterServlet")
public class RegisterServlet extends HttpServlet {
//注册信息提交,文件上传的步骤
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建磁盘工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2.创建处理工具
ServletFileUpload upload = new ServletFileUpload(factory);
//3.设置上传文件的大小
upload.setFileSizeMax(1024*1024*5);//最大可上传5M内容
String accName = "";//用户名
String accPass = "";//用户密码
String accPic = "";//用户头像
try {//4.用集合接收表单提交的全部内容
List<FileItem> fileItems = upload.parseRequest(request);
//遍历循环集合,用增强for循环foreach
for (FileItem fileItem : fileItems) {
if(fileItem.isFormField()) {//不是文件
if(fileItem.getFieldName().equals("accName")) {
//如果传过来的是accName,则值就是accName
//accName = fileItem.getString();//获取accName的值
//accName = fileItem.getString();//用户名中文传到数据库会乱码马é¹é¹,密码是非中文的不用管
accName = new String(fileItem.getString().getBytes("ISO8859-1"),"utf-8");
//但数据库依然乱码???,这里能保证accName不乱码,
//是连接数据库时乱码,在连库URL后加上?useUnicode=true&characterEncoding=utf-8
}else if(fileItem.getFieldName().equals("accPass")) {
accPass = fileItem.getString();//获取accPass的值
}
}else {//是文件,就要保存文件
//首先要取得文件的各种信息,但是要给文件重命名
//获得文件名后缀suffix,fileItem.getName()获得文件名
//如取得abc.jpg,按照.来分割,用split(".")方法分割字符串,分割成数组的两个元素,
//fileItem.getName().split(".")分割后结果是个数组,有2个元素abc和jpg,
//split(".")分割方法是支持正则的方法,.在正则表达式里表示任意字符,即会将abc.jpg分割成7个字符
//加个斜杆split("\.")表示它就是一个点,斜杆\是转义字符不能写单个斜杆,必须写两个斜杆\\,split("\\.")
String suffix = fileItem.getName().split("\\.")[1];
//给文件accPic重命名,要求上传头像的文件命名为 客户端IP+时间戳+三位1-10之间随机数.后缀
//取得客户端ip要request对象才能获取,request.getRemoteAddr()
//在工具类util中写个静态方法取得客户端ip
accPic = NewFileName.getNewFileName(request)+"."+suffix;//新的文件名
//在根目录WebContent下new个pic目录用来存放上传的头像
//保存文件
InputStream in = fileItem.getInputStream();//取得文件输入流(字节输入流)
byte[] b = new byte[(int) fileItem.getSize()];//取得集合的字节长度是个long类型要强转为int
in.read(b);//将内容读取到字节数组中
//将字节数组写入到新的文件中,文件的路径是pic路径,pic+/+新的文件名,pic路径+File.separator+accPic
//取得项目虚拟目录真实路径(在硬盘中位置),this.getServletContext()获得application对象,application.getRealPath("/pic")取得硬盘中实际运行项目的地址
File file = new File(this.getServletContext().getRealPath("/pic")+File.separator+accPic);
OutputStream out = new FileOutputStream(file);
out.write(b);//将字节数组写入到流中,把这个流写入到这个文件
in.close();
out.close();
//控制层servlet调用业务层
//将注册的用户信息保存到账户表
RegisterService service = new RegisterServiceImp();
Account account = new Account();
account.setAccName(accName);
account.setAccPass(accPass);
account.setAccPic(accPic);
service.register(account);//传递的是account对象,得将上面那些信息封装成account对象
//注册成功后跳转到登入页面,重定向到/jsp/login.jsp中
response.sendRedirect(request.getContextPath()+"/jsp/login.jsp");
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
books.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){
//加上查询条件
var bookName = "";
var pageSize = 5;//默认每页显示5笔数据
var pageCurrent = 1;//默认显示第一页
var total = 0;//数据笔数
var totalPage = 0;//总的数据页数
//从session中获取用户信息
var accId = '${account.accId}';
getAllBooks();//页面加载完成之后就执行查询方法
//查询图书信息,getAllBooks()函数
function getAllBooks(){
var url = "${pageContext.request.contextPath}/BookServlet";
var param = {
bookName:bookName,
pageSize:pageSize,
pageCurrent:pageCurrent
};
$.get(url,param,function(data){
data = eval(data);
if(data[0].code == 1002){
alert(data[0].message);
}else if(data[0].code == 1001){
total = data[0].total;//获得总数据笔数
var content = "";
var currentSize = data[0].bookInfos.length; //当前页的数据笔数
var selectAll = $("#selectAll").prop("checked");//获得全选复选框是否被选中
for(var i = 0;i<data[0].bookInfos.length;i++){
var bookInfo = data[0].bookInfos[i];
if(selectAll){
if(i == 0){ //第一笔数据跨行
content += "<tr><td><input type='checkBox' class='select' value='"+bookInfo.bookNo+"' checked></td><td>"+bookInfo.bookNo+"</td><td>"+bookInfo.bookName+"</td><td>"+bookInfo.bookPrice+"</td><td>"+bookInfo.bookStock.stockNum+"</td><td><a class='buyBook' abc='"+bookInfo.bookNo+"' href='#'>购买</a></td><td rowspan='"+currentSize+"'><input type='button' class='buyBooks' value='购买所选图书'></td></tr>";
}else{
content += "<tr><td><input type='checkBox' class='select' value='"+bookInfo.bookNo+"' checked></td><td>"+bookInfo.bookNo+"</td><td>"+bookInfo.bookName+"</td><td>"+bookInfo.bookPrice+"</td><td>"+bookInfo.bookStock.stockNum+"</td><td><a class='buyBook' abc='"+bookInfo.bookNo+"' href='#'>购买</a></td></tr>";
}
}else{
if(i == 0){ //第一笔数据跨行
content += "<tr><td><input type='checkBox' class='select' value='"+bookInfo.bookNo+"'></td><td>"+bookInfo.bookNo+"</td><td>"+bookInfo.bookName+"</td><td>"+bookInfo.bookPrice+"</td><td>"+bookInfo.bookStock.stockNum+"</td><td><a class='buyBook' abc='"+bookInfo.bookNo+"' href='#'>购买</a></td><td rowspan='"+currentSize+"'><input type='button' class='buyBooks' value='购买所选图书'></td></tr>";
}else{
content += "<tr><td><input type='checkBox' class='select' value='"+bookInfo.bookNo+"'></td><td>"+bookInfo.bookNo+"</td><td>"+bookInfo.bookName+"</td><td>"+bookInfo.bookPrice+"</td><td>"+bookInfo.bookStock.stockNum+"</td><td><a class='buyBook' abc='"+bookInfo.bookNo+"' href='#'>购买</a></td></tr>";
}
}
}
$("#showBookInfos").html(content);
}
scal();
});
}
//计算数据页数
function scal(){
if(total % pageSize == 0){
totalPage = total / pageSize;
}else{
totalPage = parseInt(total / pageSize) + 1;
}
$("#pageMessage").html("共" + total + "笔数据,当前显示第" + pageCurrent + "页,共" + totalPage + "页");
//按钮控制
$("#first").prop("disabled",false);
$("#up").prop("disabled",false);
$("#next").prop("disabled",false);
$("#last").prop("disabled",false);
if(pageCurrent == totalPage && pageCurrent == 1){//总共只有一页
$("#first").prop("disabled",true);
$("#up").prop("disabled",true);
$("#next").prop("disabled",true);
$("#last").prop("disabled",true);
}else if(pageCurrent == totalPage){ //最后一页
$("#next").prop("disabled",true);
$("#last").prop("disabled",true);
}else if(pageCurrent == 1){
$("#first").prop("disabled",true);
$("#up").prop("disabled",true);
}
}
//查询按钮事件
$("#queryForm").submit(function(){
bookName = $("input[name='bookName']").val();
pageCurrent = 1;
getAllBooks();//执行查询
return false;
});
//分页按钮事件
$("#first").click(function(){
pageCurrent = 1;
getAllBooks();//执行查询
});
$("#up").click(function(){
pageCurrent = pageCurrent - 1;
getAllBooks();//执行查询
});
$("#next").click(function(){
pageCurrent = pageCurrent + 1;
getAllBooks();//执行查询
});
$("#last").click(function(){
pageCurrent = totalPage;
getAllBooks();//执行查询
});
//下拉列表的更改选项事件
$("#changeSize").change(function(){
pageCurrent = 1;
pageSize = $(this).val();
getAllBooks();//执行查询
});
$("#logout").click(function(event){
event.preventDefault();//取消组件的默认行为
if(confirm("确认注销登录吗?")){
var href = $(this).attr("href");
window.location.href = href;//执行重定向
}
//return false;//取消超链接的默认行为
});
//买书事件
$("#showBookInfos").delegate(".buyBook","click",function(){
var bookNo = $(this).attr("abc");
var url = "${pageContext.request.contextPath}/BuyBookServlet";
var param = {
accId:accId,
bookNo:bookNo
};
$.get(url,param,function(data){
data = eval(data);
if(data[0].code == 1001){
alert(data[0].message);
getAllBooks();//执行查询
}else if(data[0].code == 1002){
alert(data[0].message);
}
});
return false;
});
//全选/全不选的操作
$("#selectAll").click(function(){
if($(this).prop("checked") == true){ //表示全选按钮被选中
$(".select").prop("checked",true);//其余的复选框全部选中
}else{
$(".select").prop("checked",false);//其余的复选框全不选中
}
});
//单独选择复选框,若全部选中的情况,全选/全不选 也必须选中
$("#showBookInfos").delegate(".select","click",function(){
if($(this).prop("checked") == true){
//如果当前的是被选种,那么得判断所有的是否都选择
//判断所有的是否都被选中
var flag = true;// 默认都被选中
var checkBoxs = $(".select"); //取得所有的复选框
for(var i = 0;i < checkBoxs.length;i++){
if($(checkBoxs[i]).prop("checked") == false){ //只要一个不被选中,flag = false
flag = false;
break;
}
}
if(flag){
$("#selectAll").prop("checked",true);
}else{
$("#selectAll").prop("checked",false);
}
}else if($(this).prop("checked") == false){
//如果当前是取消选中,那么全选/全不选 取消选中
$("#selectAll").prop("checked",false);
}
});
$("#showBookInfos").delegate(".buyBooks","click",function(){
var bookNos = "";
var checkBoxs = $(".select"); //取得所有的复选框
for(var i = 0;i < checkBoxs.length;i++){
if($(checkBoxs[i]).prop("checked") == true){ //如果被选中
bookNos += $(checkBoxs[i]).val() + ","
}
}
if(bookNos == ""){
alert("请选择要购买的图书");
return false;
}
var url = "${pageContext.request.contextPath}/buyBooksServlet";
var param = {
accId:accId,
bookNos:bookNos
};
$.get(url,param,function(data){
data = eval(data);
if(data[0].code == 1001){
alert(data[0].message);
getAllBooks();//执行查询
}else if(data[0].code == 1002){
alert(data[0].message);
}
});
});
});
</script>
</head>
<body>
<h2>XXX图书商场欢迎您:${account.accName},<a id="logout" href="${pageContext.request.contextPath}/jsp/logout.jsp">注销</a></h2>
<form id="queryForm" action="">
图书名:<input type="text" name = "bookName"> <input type="submit" value="查询">
</form>
<table border='1'>
<caption>图书信息表</caption>
<thead>
<tr>
<th><input type="checkbox" id="selectAll">全选/全不选</th>
<th>图书编号</th>
<th>图书名称</th>
<th>图书单价</th>
<th>图书库存</th>
<th>操作</th>
<th>购买多本</th>
</tr>
</thead>
<tbody id="showBookInfos"></tbody>
</table>
<input type="button" value="首页" id="first">
<input type="button" value="上一页" id="up">
<input type="button" value="下一页" id="next">
<input type="button" value="尾页" id="last">
<span id="pageMessage" style="color:blue"></span>
<span style="color:blue">,每页显示
<select id="changeSize">
<option value="3">3</option>
<option value="5" selected="selected">5</option>
<option value="10">10</option>
</select>
笔数据
</span>
</body>
</html>
login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){
$("#loginForm").submit(function(){
//在这里面做AJAX异步请求
//设置请求地址
//取得这个表单的请求地址,通过属性名action获取属性值
var url = $(this).attr("action");
//设置请求参数,这里有2个请求参数,请求参数名是name值,name="username",name="password"
//jQuery提供了val()函数取得或设置组件的值
var param = { //属性选择器
username:$("input[name='username']").val(),
password:$("#password").val()
};
//ajax函数,用post提交方式
$.post(url,param,function(data){//响应完成后的回调函数,data表示接收到的响应内容
data = eval(data);//将响应数据jsonArray转化为JSON数据格式
if(data[0].code == 1001){//data就装了一个map,data[0]就表示map
//登录成功后跳转,window.location.href等页面全部加载完成后跳转
window.location.href = "${pageContext.request.contextPath}/jsp/books.jsp";
}else if(data[0].code == 1002){
alert(data[0].message);
}
});
return false;//取消表单默认行为,submit默认提交行为
});
});
</script>
</head>
<body>
<form method="post" id="loginForm" action="${pageContext.request.contextPath}/LoginServlet">
用户名:<input type="text" name="username">
密码:<input type="password" name="password" id="password">
<input type="submit" value="登录">
<a href="register.jsp">注册</a>
</form>
</body>
</html>
logout.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
session.invalidate();//让session失效
response.sendRedirect("login.jsp");//重定向到登录页
%>
</body>
</html>
register.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
//验证两次输入密码必须一致
$(function(){
var accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
//jQuery对象$("#registerForm")调submit事件,submit提交的组件,点击submit触发函数
$("#registerForm").submit(function(){
if(!accNameCheck){ //accNameCheck响应的信息控制表单能否提交的问题
alert("用户名不可用"); //true才执行if,false进不来if
return false;
}
//取得两次输入的密码
//var pass = $("#accName").addr("value")
//取某个标签的值不是用addr取value属性
var pass= $("#accPass").val();
//jQuery提供了val()函数取得或设置组件的值
var passAgain = $("#accPassAgain").val();//取得第二次输入的密码
var name = $("#accName").val();
if(name == "" || null == name ){
alert("用户名不能为空");
return false;//取消组件的默认行为
//取消表单submit提交按钮的提交默认行为
}
if(pass == "" || null == pass){
alert("密码不能为空");
return false;
}
if(pass != passAgain){
alert("两次输入密码不一致");
return false;
}
});
//给这个用户名一个失去焦点的事件(blur)
$("#accName").blur(function(){
var accName = $(this).val();
var param = {
accName : accName//js中对象的写法
};
var url = "${pageContext.request.contextPath}/RegisterCheckServlet";
$.get(url,param,function(data){//参数3响应完成后的回调函数,data表示接收到的响应内容
if(data == "true" || data == true){
$("#checkMessage").html("<font style = 'color:green'>用户名可用</font>");
accNameCheck = true;//accNameCheck响应的信息控制表单能否提交的问题
}else{
$("#checkMessage").html("<font style = 'color:red'>用户名不可用</font>");
accNameCheck = false;//accNameCheck响应的信息控制表单能否提交的问题
}
});
});
});
</script>
</head>
<body> <!-- 注册jsp提交到注册Servlet -->
<form id="registerForm" action="${pageContext.request.contextPath}/RegisterServlet"
enctype="multipart/form-data" method="post">
用户名:<input type="text" name="accName" id="accName"><span id = "checkMessage"></span>
<br>
密码 : <input type="password" name="accPass" id="accPass">
<br>
再次输入密码 : <input type="password" name="accPassAgain" id="accPassAgain">
<br>
头像 : <input type="file" name="accPic">
<br>
<input type="submit" value="注册">
</form>
</body>
</html>