注册:
验证码信息存放在session中。
防止重复提交表单,详见:https://blog.csdn.net/YooFale/article/details/86576025
具体实现:先findByUsername,再save。
激活:先findByCode,再updateStatus。(也可以在完成激活后清除code),需要涉及到MailUtil的发送邮件操作。
登录:findByUsernameAndPassword,登陆完成需要把用户信息存储到session中。
查询:findAll实现,
public List findAll() {
// 从redis中查询
Jedis jedis = JedisUtil.getJedis();
// Set categorys = jedis.zrange("category", 0, -1);
Set categorys = jedis.zrangeWithScores("category", 0, -1);
List categoryList = null;
// 判断是否为空
if (categorys == null || categorys.size() == 0) {
// 为空第一次访问,需要从数据库查询,并存储在redis中
categoryList = categoryDao.findAll();
for (int i = 0; i < categoryList.size(); i++) {
jedis.zadd("category", categoryList.get(i).getCid(), categoryList.get(i).getCname());
}
} else {
// 不为空,证明不是第一次,将redis中的数据存储到list中返回(set转存到list中)
categoryList = new ArrayList();
// for (String name:categorys){
// Category category = new Category();
// category.setCname(name);
// categoryList.add(category);
// }
for (Tuple tuple : categorys) {
Category category = new Category();
category.setCname(tuple.getElement());
category.setCid((int) tuple.getScore());
categoryList.add(category);
}
}
return categoryList;
}
zrange用于按照权重(score)查询redis中存储的数据。zrangeWithScores查询的结果不仅是数据,还有对应的score。
redis中查不到需要dao,zadd(key,score,value)用于向redis中存储。
在redis中能查到,需要把redis中set格式的数据转存到list中,并返回前端。
首先确立pageBean的五大元素。前端需要提供的是currentPage,pageSize,cid(分类id)。
int cid =0;
// 处理参数
if(cidStr!=null && cidStr.length()>0 && !"null".equals(cidStr)){
cid = Integer.parseInt(cidStr);
}
int pageSize = 0;
// 处理参数
if(pageSizeStr!=null && pageSizeStr.length()>0){
pageSize = Integer.parseInt(pageSizeStr);
}else{
pageSize=5;
}
int currentPage =0;
// 处理参数
if(currentPageStr!=null && currentPageStr.length()>0){
currentPage = Integer.parseInt(currentPageStr);
}else{
currentPage = 1;
}
需要注意的是,cid可能为“null”。
header.html
$("#search_button").click(function () {
var rname = $("#search_input").val();
var cid = getParameter("cid");
// 页面跳转
location.href="http://localhost:8080/travel/route_list.html?cid="+cid+"&&rname="+rname;
});
点击按钮地址跳转
route_list.html
var cid = getParameter("cid");
var rname = getParameter("rname");
if(rname){
rname = window.decodeURIComponent(rname);
}
//当页码加载完成后,调用load方法,发送ajax请求加载数据
load(cid,null,rname);
页面加载完成获取地址栏的参数,调用方法(currentPage为null)加载数据。
tomcat7无法处理乱码,需要手动转码:
String rname = request.getParameter("rname");
rname = new String(rname.getBytes("iso-8859-1"), "utf-8");
domain中route不仅有tab_route中的属性,还有额外的关联对象 category,seller,routeImageList等
在卖家表,路线表,路线图片表三个表完成查询后,统一写入route对象中。
需要注意的部分多为回显,在JQ中。
在JQ中,html方法相当于JS中的innerHtml。
界面上用户名的回显利用存储在session中的用户信息来完成。
window.scrollTo(0,0);定位到页面顶部
prop方法:设置属性和值
addClass方法:向元素添加一个类
removeAttr方法:移除元素的某个方法
两大难点:
一。分页显示
function load(cid ,currentPage,rname){
//发送ajax请求,请求route/pageQuery,传递cid
$.get("route/pageQuery",{cid:cid,currentPage:currentPage,rname:rname},function (pb) {
//1.分页工具条数据展示
//1.1 展示总页码和总记录数
$("#totalPage").html(pb.totalPage);
$("#totalCount").html(pb.totalCount);
var lis = "";
var fristPage = '首页 ';
//计算上一页的页码
var beforeNum = pb.currentPage - 1;
if(beforeNum <= 0){
beforeNum = 1;
}
var beforePage = '上一页 ';
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 = ''+i+' ';
}else{
//创建页码的li
li = ''+i+' ';
}
//拼接字符串
lis += li;
}
/* for (var i = 1; i <= pb.totalPage ; i++) {
var li;
//判断当前页码是否等于i
if(pb.currentPage == i){
li = ''+i+' ';
}else{
//创建页码的li
li = ''+i+' ';
}
//拼接字符串
lis += li;
}*/
var lastPage = '末页 ';
var nextPage = '下一页 ';
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 = '\n' +
' \n' +
' \n' +
' '+route.rname+'
\n' +
'
\n' +
' '+route.routeIntroduce+'
\n' +
' \n' +
' \n' +
' \n' +
' ¥\n' +
' '+route.price+'\n' +
' 起\n' +
'
\n' +
' \n' +
' \n' +
' ';
route_lis += li;
}
$("#route").html(route_lis);
//定位到页面顶部
window.scrollTo(0,0);
});
}
指定start,end的范围,确保页数控制在10左右。且当前页有额外的样式。
二。路线详情
图片拼接显示的一般控制在4张,所以遍历中i>4的时候,style:“display:none”;
收藏按钮:
var rid = getParameter("rid");
$.get("route/isFavorite",{rid:rid},function (flag) {
if(flag){
// 用户已经收藏过
//
//设置收藏按钮的样式
$("#favorite").addClass("already");
$("#favorite").attr("disabled","disabled");
//删除按钮的点击事件
$("#favorite").removeAttr("onclick");
}else{
// 用户没有收藏
}
});
public int findTotalCount(int cid,String rname) {
String sql = "select count(*) from tab_route where 1=1 ";
StringBuilder sb = new StringBuilder(sql);
List params = new ArrayList();
// 判断参数
if(cid!=0){
sb.append(" and cid = ? ");
params.add(cid);
}
if(rname !=null && rname.length() >0){
sb.append(" and rname like ?");
params.add("%"+rname+"%");
}
sql = sb.toString();
return jdbcTemplate.queryForObject(sql, Integer.class,params.toArray());
}
需要注意分页查询的时候可能涉及到搜索和全查询,所以需要拼接sql。
JdbcTemplate中queryForObject查询不到内容会抛异常而不是返回null,在知道可能查询不到的情况下最好的处理方式是先声明为null,再将查询语句try/catch处理。
在整合的时候,对一个类的操作要整合到同一个servlet中,在BaseServlet中有如下方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// System.out.println("BaseServlet的service方法被执行了");
// 完成方法的分发
// 1.获取请求路径
String uri = req.getRequestURI(); // /travel/user/add
// 2.获取方法名称
String methodNName = uri.substring(uri.lastIndexOf('/') + 1);
// 3.获取方法对象Method
//System.out.println(this); 此时userServlet调用,所以this是userServlet
try {
//因为是protected,所以需要忽略权限,并添加暴力反射
Method method = this.getClass().getMethod(methodNName, 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();
}
}
service必定执行,获取路径最后的具体名,因为方法调用者是本身的servlet,所以通过反射可以直接调用具体的方法。
public void writeValue(Object object,HttpServletResponse response) throws IOException {
ObjectMapper mapper = new ObjectMapper();
response.setContentType("application/json;charset=utf-8");
mapper.writeValue(response.getOutputStream(), object);
}
writeValue方法用于将结果写为json格式并以字节输出流的格式返回。