1. 程式人生 > 其它 >JavaWebDay26(旅遊網專案2)36

JavaWebDay26(旅遊網專案2)36

綜合案例

優化Servlet

目的

減少Servlet的數量,現在是一個功能一個Servlet,將其優化為一個模組一個Servlet,相當於在資料庫中一張表對應一個Servlet,在Servlet中提供不同的方法,完成使用者的請求。

BaseServlet編寫:

public class BaseServlet extends HttpServlet {


@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//System.out.println("baseServlet的service方法被執行了...");

//完成方法分發
//1.獲取請求路徑
String uri = req.getRequestURI(); // /travel/user/add
System.out.println("請求uri:"+uri);// /travel/user/add
//2.獲取方法名稱
String methodName = uri.substring(uri.lastIndexOf('/') + 1);
System.out.println("方法名稱:"+methodName);
//3.獲取方法物件Method
//誰呼叫我?我代表誰
System.out.println(this);//UserServlet的物件cn.itcast.travel.web.servlet.UserServlet@4903d97e
try {
//獲取方法
Method method = this.getClass().getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//4.執行方法
//暴力反射
//method.setAccessible(true);
method.invoke(this,req,resp);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

UserServlet改寫

將之前的Servlet實現的功能,抽取到UserServlet中的不同方法中實現,並且將UserService建立抽取到成員變數位置

@WebServlet("/user/*") // /user/add /user/find
public class UserServlet extends BaseServlet {

//宣告UserService業務物件
private UserService service = new UserServiceImpl();

/**
* 註冊功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

//驗證校驗
String check = request.getParameter("check");
//從sesion中獲取驗證碼
HttpSession session = request.getSession();
String checkcode_server = (String) session.getAttribute("CHECKCODE_SERVER");
session.removeAttribute("CHECKCODE_SERVER");//為了保證驗證碼只能使用一次
//比較
if(checkcode_server == null || !checkcode_server.equalsIgnoreCase(check)){
//驗證碼錯誤
ResultInfo info = new ResultInfo();
//註冊失敗
info.setFlag(false);
info.setErrorMsg("驗證碼錯誤");
//將info物件序列化為json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);
return;
}

//1.獲取資料
Map<String, String[]> map = request.getParameterMap();

//2.封裝物件
User user = new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

//3.呼叫service完成註冊
//UserService service = new UserServiceImpl();
boolean flag = service.regist(user);
ResultInfo info = new ResultInfo();
//4.響應結果
if(flag){
//註冊成功
info.setFlag(true);
}else{
//註冊失敗
info.setFlag(false);
info.setErrorMsg("註冊失敗!");
}

//將info物件序列化為json
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(info);

//將json資料寫回客戶端
//設定content-type
response.setContentType("application/json;charset=utf-8");
response.getWriter().write(json);

}

/**
* 登入功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取使用者名稱和密碼資料
Map<String, String[]> map = request.getParameterMap();
//2.封裝User物件
User user = new User();
try {
BeanUtils.populate(user,map);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

//3.呼叫Service查詢
// UserService service = new UserServiceImpl();
User u = service.login(user);

ResultInfo info = new ResultInfo();

//4.判斷使用者物件是否為null
if(u == null){
//使用者名稱密碼或錯誤
info.setFlag(false);
info.setErrorMsg("使用者名稱密碼或錯誤");
}
//5.判斷使用者是否啟用
if(u != null && !"Y".equals(u.getStatus())){
//使用者尚未啟用
info.setFlag(false);
info.setErrorMsg("您尚未啟用,請啟用");
}
//6.判斷登入成功
if(u != null && "Y".equals(u.getStatus())){
request.getSession().setAttribute("user",u);//登入成功標記

//登入成功
info.setFlag(true);
}

//響應資料
ObjectMapper mapper = new ObjectMapper();

response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),info);
}

/**
* 查詢單個物件
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//從session中獲取登入使用者
Object user = request.getSession().getAttribute("user");
//將user寫回客戶端

ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),user);
}

/**
* 退出功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void exit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.銷燬session
request.getSession().invalidate();

//2.跳轉登入頁面
response.sendRedirect(
request.getContextPath()+"/login.html");
}

/**
* 啟用功能
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void active(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.獲取啟用碼
String code = request.getParameter("code");
if(code != null){
//2.呼叫service完成啟用
//UserService service = new UserServiceImpl();
boolean flag = service.active(code);

//3.判斷標記
String msg = null;
if(flag){
//啟用成功
msg = "啟用成功,請<a href='login.html'>登入</a>";
}else{
//啟用失敗
msg = "啟用失敗,請聯絡管理員!";
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write(msg);
}
}
}

頁面路徑改寫

分類資料展示

分析:

程式碼實現:

後臺程式碼

CategoryServlet

@WebServlet("/category/*")
public class CategoryServlet extends BaseServlet {

private CategoryService service = new CategoryServiceImpl();

/**
* 查詢所有
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void findAll(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.呼叫service查詢所有
List<Category> cs = service.findAll();
//2.序列化json返回
/* ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),cs);*/
writeValue(cs,response);

}

}

CategoryService

public class CategoryServiceImpl implements CategoryService {

private CategoryDao categoryDao = new CategoryDaoImpl();

@Override
public List<Category> findAll() {
return categoryDao.findAll();
}
}

CategoryDao
public class CategoryDaoImpl implements CategoryDao {

private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

@Override
public List<Category> findAll() {
String sql = "select * from tab_category ";
return template.query(sql,new BeanPropertyRowMapper<Category>(Category.class));
}
}

在BaseServlet中封裝了序列化json的方法

/**
* 直接將傳入的物件序列化為json,並且寫回客戶端
* @param obj
*/
public void writeValue(Object obj,HttpServletResponse response) throws IOException {
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(),obj);
}

/**
* 將傳入的物件序列化為json,返回
* @param obj
* @return
*/
public String writeValueAsString(Object obj) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(obj);
}

前臺程式碼

hader.html載入後,傳送ajax請求,請求category/findAll

//查詢分類資料
$.get("category/findAll",{},function (data) {
//[{cid:1,cname:國內遊},{},{}]
var lis = '<li class="nav-active"><a href="index.html">首頁</a></li>';
//遍歷陣列,拼接字串(<li>)
for (var i = 0; i < data.length; i++) {
var li = '<li><a href="route_list.html">'+data[i].cname+'</a></li>';

lis += li;

}
//拼接收藏排行榜的li,<li><a href="favoriterank.html">收藏排行榜</a></li>

lis+= '<li><a href="favoriterank.html">收藏排行榜</a></li>';

//將lis字串,設定到ul的html內容中
$("#category").html(lis);
});

對分類資料進行快取優化

分析發現,分類的資料在每一次頁面載入後都會重新請求資料庫來載入,對資料庫的壓力比較大,而且分類的資料不會經常產生變化,所有可以使用redis來快取這個資料。 分析:

優化程式碼實現

期望資料中儲存的順序就是將來展示的順序,使用redis的sortedset

@Override
public List<Category> findAll() {
//1.從redis中查詢
//1.1獲取jedis客戶端
Jedis jedis = JedisUtil.getJedis();
//1.2可使用sortedset排序查詢
Set<String> categorys = jedis.zrange("category", 0, -1);
List<Category> cs = null;
//2.判斷查詢的集合是否為空
if (categorys == null || categorys.size() == 0) {

System.out.println("從資料庫查詢....");
//3.如果為空,需要從資料庫查詢,在將資料存入redis
//3.1 從資料庫查詢
cs = categoryDao.findAll();
//3.2 將集合資料儲存到redis中的 category的key
for (int i = 0; i < cs.size(); i++) {

jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname());
}
} else {
System.out.println("從redis中查詢.....");

//4.如果不為空,將set的資料存入list
cs = new ArrayList<Category>();
for (String name : categorys) {
Category category = new Category();
category.setCname(name);
cs.add(category);

}
}
return cs;
}

旅遊線路的分頁展示

點選了不同的分類後,將來看到的旅遊線路不一樣的。通過分析資料庫表結構,發現,旅遊線路表和分類表時一個多對一的關係

查詢不同分類的旅遊線路sql Select * from tab_route where cid = ?;

類別id的傳遞

Redis中查詢score(cid)

public class CategoryServiceImpl implements CategoryService {

private CategoryDao categoryDao = new CategoryDaoImpl();

@Override
public List<Category> findAll() {
//1.從redis中查詢
//1.1獲取jedis客戶端
Jedis jedis = JedisUtil.getJedis();
//1.2可使用sortedset排序查詢
//Set<String> categorys = jedis.zrange("category", 0, -1);
//1.3查詢sortedset中的分數(cid)和值(cname)
Set<Tuple> categorys = jedis.zrangeWithScores("category", 0, -1);

List<Category> cs = null;
//2.判斷查詢的集合是否為空
if (categorys == null || categorys.size() == 0) {

System.out.println("從資料庫查詢....");
//3.如果為空,需要從資料庫查詢,在將資料存入redis
//3.1 從資料庫查詢
cs = categoryDao.findAll();
//3.2 將集合資料儲存到redis中的 category的key
for (int i = 0; i < cs.size(); i++) {

jedis.zadd("category", cs.get(i).getCid(), cs.get(i).getCname());
}
} else {
System.out.println("從redis中查詢.....");

//4.如果不為空,將set的資料存入list
cs = new ArrayList<Category>();
for (Tuple tuple : categorys) {
Category category = new Category();
category.setCname(tuple.getElement());
category.setCid((int)tuple.getScore());
cs.add(category);

}
}


return cs;
}
}

頁面傳遞cid header.html傳遞cid

var li = '<li><a href="route_list.html?cid='+data[i].cid+'">'+data[i].cname+'</a></li>';

獲取cid

$(function () {
var search = location.search;
//alert(search);//?id=5
// 切割字串,拿到第二個值
var cid = search.split("=")[1];
});

根據id查詢不同類別的旅遊線路資料

分頁展示旅遊線路資料:

分析

編碼

客戶端程式碼編寫

$(function () {
var search = location.search;
// 切割字串,拿到第二個值
var cid = search.split("=")[1];

//當頁碼載入完成後,呼叫load方法,傳送ajax請求載入資料
load(cid);
});

function load(cid ,currentPage){
//傳送ajax請求,請求route/pageQuery,傳遞cid
$.get("route/pageQuery",{cid:cid,currentPage:currentPage},function (pb) {
//解析pagebean資料,展示到頁面上

//1.分頁工具條資料展示
//1.1 展示總頁碼和總記錄數
$("#totalPage").html(pb.totalPage);
$("#totalCount").html(pb.totalCount);

var lis = "";

var fristPage = '<li onclick="javascipt:load('+cid+')"><a href="javascript:void(0)">首頁</a></li>';

//計算上一頁的頁碼
var beforeNum = pb.currentPage - 1;
if(beforeNum <= 0){
beforeNum = 1;
}

var beforePage = '<li onclick="javascipt:load('+cid+','+beforeNum+')" class="threeword"><a href="javascript:void(0)">上一頁</a></li>';

lis += fristPage;
lis += beforePage;
//1.2 展示分頁頁碼
/*
1.一共展示10個頁碼,能夠達到前5後4的效果
2.如果前邊不夠5個,後邊補齊10個
3.如果後邊不足4個,前邊補齊10個
*/

// 定義開始位置begin,結束位置 end
var begin; // 開始位置
var end ; // 結束位置


//1.要顯示10個頁碼
if(pb.totalPage < 10){
//總頁碼不夠10頁

begin = 1;
end = pb.totalPage;
}else{
//總頁碼超過10頁

begin = pb.currentPage - 5 ;
end = pb.currentPage + 4 ;

//2.如果前邊不夠5個,後邊補齊10個
if(begin < 1){
begin = 1;
end = begin + 9;
}

//3.如果後邊不足4個,前邊補齊10個
if(end > pb.totalPage){
end = pb.totalPage;
begin = end - 9 ;
}
}


for (var i = begin; i <= end ; i++) {
var li;
//判斷當前頁碼是否等於i
if(pb.currentPage == i){

li = '<li class="curPage" onclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';

}else{
//建立頁碼的li
li = '<li onclick="javascipt:load('+cid+','+i+')"><a href="javascript:void(0)">'+i+'</a></li>';
}
//拼接字串
lis += li;
}





var lastPage = '<li class="threeword"><a href="javascript:;">末頁</a></li>';
var nextPage = '<li class="threeword"><a href="javascript:;">下一頁</a></li>';

lis += nextPage;
lis += lastPage;


//將lis內容設定到 ul
$("#pageNum").html(lis);




//2.列表資料展示
var route_lis = "";

for (var i = 0; i < pb.list.length; i++) {
//獲取{rid:1,rname:"xxx"}
var route = pb.list[i];

var li = '<li>\n' +
' <div class="img"><img src="'+route.rimage+'" style="width: 299px;"></div>\n' +
' <div class="text1">\n' +
' <p>'+route.rname+'</p>\n' +
' <br/>\n' +
' <p>'+route.routeIntroduce+'</p>\n' +
' </div>\n' +
' <div class="price">\n' +
' <p class="price_num">\n' +
' <span>&yen;</span>\n' +
' <span>'+route.price+'</span>\n' +
' <span>起</span>\n' +
' </p>\n' +
' <p><a href="route_detail.html">檢視詳情</a></p>\n' +
' </div>\n' +
' </li>';
route_lis += li;
}
$("#route").html(route_lis);

//定位到頁面頂部
window.scrollTo(0,0);
});

}

伺服器端程式碼編寫

建立PageBean物件

public class PageBean<T> {

private int totalCount;//總記錄數
private int totalPage;//總頁數
private int currentPage;//當前頁碼
private int pageSize;//每頁顯示的條數

private List<T> list;//每頁顯示的資料集合

public int getTotalCount() {
return totalCount;
}

public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}

public int getTotalPage() {
return totalPage;
}

public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}

public int getCurrentPage() {
return currentPage;
}

public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}

public int getPageSize() {
return pageSize;
}

public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}

public List<T> getList() {
return list;
}

public void setList(List<T> list) {
this.list = list;
}
}

RouteServlet

@WebServlet("/route/*")
public class RouteServlet extends BaseServlet {

private RouteService routeService = new RouteServiceImpl();

/**
* 分頁查詢
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
public void pageQuery(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.接受引數
String currentPageStr = request.getParameter("currentPage");
String pageSizeStr = request.getParameter("pageSize");
String cidStr = request.getParameter("cid");

int cid = 0;//類別id
//2.處理引數
if(cidStr != null && cidStr.length() > 0){
cid = Integer.parseInt(cidStr);
}
int currentPage = 0;//當前頁碼,如果不傳遞,則預設為第一頁
if(currentPageStr != null && currentPageStr.length() > 0){
currentPage = Integer.parseInt(currentPageStr);
}else{
currentPage = 1;
}

int pageSize = 0;//每頁顯示條數,如果不傳遞,預設每頁顯示5條記錄
if(pageSizeStr != null && pageSizeStr.length() > 0){
pageSize = Integer.parseInt(pageSizeStr);
}else{
pageSize = 5;
}

//3. 呼叫service查詢PageBean物件
PageBean<Route> pb = routeService.pageQuery(cid, currentPage, pageSize);

//4. 將pageBean物件序列化為json,返回
writeValue(pb,response);

}

}

RouteService
public class RouteServiceImpl implements RouteService {
private RouteDao routeDao = new RouteDaoImpl();
@Override
public PageBean<Route> pageQuery(int cid, int currentPage, int pageSize) {
//封裝PageBean
PageBean<Route> pb = new PageBean<Route>();
//設定當前頁碼
pb.setCurrentPage(currentPage);
//設定每頁顯示條數
pb.setPageSize(pageSize);

//設定總記錄數
int totalCount = routeDao.findTotalCount(cid);
pb.setTotalCount(totalCount);
//設定當前頁顯示的資料集合
int start = (currentPage - 1) * pageSize;//開始的記錄數
List<Route> list = routeDao.findByPage(cid,start,pageSize);
pb.setList(list);

//設定總頁數 = 總記錄數/每頁顯示條數
int totalPage = totalCount % pageSize == 0 ? totalCount / pageSize :(totalCount / pageSize) + 1 ;
pb.setTotalPage(totalPage);


return pb;
}
}

RouteDao
public class RouteDaoImpl implements RouteDao {
private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());

@Override
public int findTotalCount(int cid) {
String sql = "select count(*) from tab_route where cid = ?";
return template.queryForObject(sql,Integer.class,cid);
}

@Override
public List<Route> findByPage(int cid, int start, int pageSize) {
String sql = "select * from tab_route where cid = ? limit ? , ?";

return template.query(sql,new BeanPropertyRowMapper<Route>(Route.class),cid,start,pageSize);
}
}