访问案例网站时默认调用index.jsp,在此页面设定转向MainSvl。
http://localhost:8080/BookShop
新建index.jsp
<%request.getRequestDispatcher("/MainSvl").forward(request, response);%>
新建MainSvl(控制层)
@WebServlet("/MainSvl")
public class MainSvl extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BookBiz biz = new BookBiz();
try {
List<TBook> books = biz.getAllBooks();
request.setAttribute("books", books);
request.getRequestDispatcher("/WEB-INF/main/main.jsp").forward(request, response);
}catch(Exception e){
request.setAttribute("msg", "网路异常,请跟网站管理员联系。");
request.getRequestDispatcher("/error.jsp").forward(request, response);
}
}
(余略)
}
新建BookBiz(服务层)
public class BookBiz {
public List<TBook> getAllBooks() throws Exception{
IBookDao dao = new BookDaoMysql();
try {
return dao.getAllBooks();
}finally{
dao.closeConnection();
}
}
}
新建BookDaoMysql(持久层:负责DB访问)
public class BookDaoMysql extends BaseDao{
public List<TBook> getAllBooks() throws Exception{
List<TBook> books = null;
String sql = "select isbn,name,press,price,pdate from tbook order by isbn";
//从BaseDao取得connection = DriverManager.getConnection(dbInfo.getUrl(), dbInfo.getUname(), dbInfo.getPwd());
this.openConnection();
PreparedStatement ps = this.connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
if(rs != null) {
books = new ArrayList<TBook>();
//当rs里面还有下一件资料时
while(rs.next()) {
//把取出的资料都保存到TBook物件中
TBook bk = new TBook();
bk.setBname(rs.getString("bname"));
bk.setIsbn(rs.getString("isbn"));
bk.setPdate(rs.getString("Pdate"));
bk.setPress(rs.getString("press"));
bk.setPrice(rs.getString("price"));
//将TBook物件加入列表
books.add(bk);
}
}
return books;
使用JSTL的<c:forEath>标签即可简单取出列表
var为保存资料用的变数名(可自取),items为资料来源列表的名字。
<table border="1" width=100%>
<c:forEach var="bk" items="${books }">
<tr>
<td rowspan=3>
<img width=100 height=100 src="<%=basePath%>BookPicSvl?isbn=${bk.isbn }">
</td>
<td colspan=2 align=center style="color:red">
<a href="<%=basePath%>BookDetailSvl?isbn=${bk.isbn }">${bk.bname }</a>
</td>
</tr>
<tr><td>商品价格</td><td>${bk.price }</td></tr>
<tr><td>出版社</td><td>${bk.press }</td></tr>
</c:forEach>
</table>
在这个案例中,使用了标签和<%=basePath%>,这两个部分是常用的代码,可以抽取出来放在base.jsp页面中。
使用以下指令进行静态引用
<%@include file ="/WEB-INF/base.jsp" %>
另外一种引用方法为动态引用,不过动态引用就无法取得base页面里的变数。得要在页面静态编译时便建立好变数才能引用。
<jsp:include page="/WEB-INF/base.jsp"></jsp:include>
c标签也有引用页面的import方法
<c:import url="base.jsp"></c:import>
不过这样做的话就必须先加载以下标签库
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
在本案例中标签库的加载交给base页面做了,所以选择include file指令更方便。
当用户进行下载图片等比较耗时的处理,可以使用NIO(非阻塞流)技术(一种异步处理技术)。
新建BookPicSvl并开启支援异步模式。
@WebServlet(urlPatterns="/BookPicSvl",asyncSupported=true)
public class BookPicSvl extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String isbn = request.getParameter("isbn");
if(isbn == null) {
throw new RuntimeException("isbn不能为空");
}
BookBiz biz = new BookBiz();
try {
byte[] pic = biz.getBookPic(isbn);
if(pic != null) {
AsyncContext acontext = request.startAsync();
ServletOutputStream out = acontext.getResponse().getOutputStream();
out.setWriteListener(new MyPicWriter(out,acontext,pic));
}
}catch(Exception e){
Log.logger.error(e.getMessage(), e);
request.setAttribute("msg", "网路异常,请检查。");
request.getRequestDispatcher("/error.jsp").forward(request, response);
}
}
(余略)
}
新建MyPicWriter
public class MyPicWriter implements WriteListener {
private ServletOutputStream out;
private AsyncContext ac;
private byte[] pic;
public MyPicWriter(ServletOutputStream out,AsyncContext ac,byte[] pic) {
this.ac = ac;
this.out = out;
this.pic = pic;
}
@Override
public void onError(Throwable t) {
t.printStackTrace();
}
@Override
public void onWritePossible() throws IOException {
try {
if(pic != null && out.isReady()) {
out.write(pic);
//out.flush(); --此处不能使用flush
out.close();
}
}catch(Exception e){
e.printStackTrace();
}finally {
ac.complete();
}
}
}
当图片资料不为空,且输出流已经准备好时,使用write(pic)将资料写出後关闭输出流。最後关闭异步处理物件。
服务层的动作
public class BookBiz {
public byte[] getBookPic(String isbn) throws Exception{
IBookDao dao = new BookDaoMysql();
try {
return dao.getBookPic(isbn);
}finally{
dao.closeConnection();
}
}
}
DAO层的动作
public class BookDaoMysql extends BaseDao{
public byte[] getBookPic(String isbn) throws Exception{
byte[] pic = null;
String sql = "select pic from tbook where isbn = ?";
this.openConnection();
PreparedStatement ps = this.connection.prepareStatement(sql);
ps.setString(1, isbn);
ResultSet rs = ps.executeQuery();
if(rs != null) {
while(rs.next()) {
pic = rs.getBytes("pic");
break;
}
}
rs.close();
ps.close();
return pic;
}
}
利用特定条件取得资料时,SQL文内会放置"?"占位符。跟取得全部列表时不一样。
当SQL文内有占位符时,依照其数量,使用PreparedStatement物件的setString(index, value)将值代入;
例如ps.setString(1, isbn);,意思是将isbn变数内的值代入第一个占位符内。
使用while回圈来确保至少有一行资料,然後将其读取。
疑问:之前的教材中没有关闭rs和ps,不知道为什麽。
在main.jsp和BookDetail.jsp中,使用标签来请求图片的数据流。
<img src="<%=basePath%>BookPicSvl?isbn=${bk.isbn}"/>
在首页列表中点击任一商品之後,跳转到商品细节页面。连结长得像下面这样
http://localhost:8080/BookShop/BookDetailSvl?isbn=is001
新建BookDetailSvl
@WebServlet("/BookDetailSvl")
public class BookDetailSvl extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String isbn = request.getParameter("isbn");
if(isbn == null) {
throw new RuntimeException("isbn不能为空");
}
BookBiz biz = new BookBiz();
try {
TBook book = biz.getBookDetail(isbn);
request.setAttribute("book", book);
request.getRequestDispatcher("/WEB-INF/main/BookDetail.jsp").forward(request, response);
}catch(Exception e){
Log.logger.error(e.getMessage(),e);
request.setAttribute("msg", "网路异常,请跟网站管理员联系。");
request.getRequestDispatcher("/error.jsp").forward(request, response);
}
}
}
服务层
新增getBookDetail(isbn)方法
public TBook getBookDetail(String isbn) throws Exception{
IBookDao dao = new BookDaoMysql();
try {
return dao.getBookDetail(isbn);
}finally{
dao.closeConnection();
}
}
DAO层
新增getBookDetail(String isbn)方法
public TBook getBookDetail(String isbn) throws Exception{
TBook book = null;
String sql = "select isbn,bname,press,price,pdate from tbook where isbn = ?";
this.openConnection();
PreparedStatement ps = this.connection.prepareStatement(sql);
ps.setString(1, isbn);
ResultSet rs = ps.executeQuery();
if(rs != null) {
while(rs.next()) {
book.setBname(rs.getString("bname"));
book.setIsbn(rs.getString("isbn"));
book.setPdate(rs.getString("Pdate"));
book.setPress(rs.getString("press"));
book.setPrice(rs.getString("price"));
break;
}
}
return book;
}
BookDetail.jsp页面
(前略)
<table border="1" width=100%>
<tr>
<td rowspan=3>
<img width=100 height=100 src="<%=basePath%>BookPicSvl?isbn=${book.isbn }">
</td>
<td colspan=2 align=center style="color:red">
${book.bname }
</td>
</tr>
<tr><td>商品价格</td><td>${book.price }</td></tr>
<tr><td>出版社</td><td>${book.press }</td></tr>
<tr><td height=300 colspan=3>图书简介</td></tr>
<tr><td colspan=3 align="center">
<a href="<%=basePath%>user/ShopCarAddSvl?isbn=${book.isbn }">加入购物车</a>
<a href="<%=basePath%>MainSvl">返回</a>
</td>
</tr>
</table>
<<: 资产分类准则(asset classification guideline)
前言 目前为止我们都专注在解释辞法范围,以及他会对程序中的变量与使用产生什麽影响,本章节会将角度转移...
在写for回圈的时候,每次都需要输入for回圈的条件式,宣告int I, i<某数, i++ ...
将几篇 Boxenn 相关文章整理成分类目录(范例 GitHub repository 建置中,完成...
接下来Day4-6的用法,都是由Ruby的Enumerable。Enumerable 是Ruby相当...
理解了 IP 位置的组成,我们接着来看看一些常被提到的相关名词:浮动、固定及虚拟 IP 位置。 浮动...