Maven 项目启动,我们可以通过配置 Tomcat 插件来启动
<!--tomcat插件--> <plugin> <groupId>org.apache.tomcat.maven</groupId> <!-- tomcat7的插件, 不同tomcat版本这个也不一样 --> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.1</version> <configuration> <!-- 通过maven tomcat7:run运行项目时,访问项目的端口号 --> <port>8080</port> <!-- 项目访问路径 本例:localhost:9090, 如果配置的aa, 则访问路径为localhost:9090/aa--> <path>/travel</path> </configuration> </plugin>为了不每次启动项目都要去找这个命令,我们可以配置一下。后面我们启动直接点击启动的那个按钮即可
用户表,存储的和用户相关的信息
/** * 用户实体类 */ public class User implements Serializable { private int uid;//用户id private String username;//用户名,账号 private String password;//密码 private String name;//真实姓名 private String birthday;//出生日期 private String sex;//男或女 private String telephone;//手机号 private String email;//邮箱 private String status;//激活状态,Y代表激活,N代表未激活 private String code;//激活码(要求唯一) //省略 get set toString 构造函数等方法 }
tab_category 存储的就是上面导航栏里面的信息,这里我们是从数据库里面去取出来,而不是写死,返回的是 json 数据
[{"cid":8,"cname":"全球自由行"},{"cid":5,"cname":"国内游"},{"cid":4,"cname":"处境游"},{"cid":7,"cname":"抱团定制"},{"cid":6,"cname":"港澳游"},{"cid":2,"cname":"酒店"},{"cid":1,"cname":"门票"},{"cid":3,"cname":"香港车票"}] //重数据库(tab_category)里面查询分类信息,填充到页面 $.get("category/findAll", {}, function (data) { console.log(data); //[{"cid":8,"cname":"全球自由行"},{"cid":5,"cname":"国内游"},{"cid":4,"cname":"处境游"},{"cid":7,"cname":"抱团定制"},{"cid":6,"cname":"港澳游"},{"cid":2,"cname":"酒店"},{"cid":1,"cname":"门票"},{"cid":3,"cname":"香港车票"}] //收尾的两个 li 是固定的 var first = '<li class="nav-active"><a href="index.html">首页</a></li>'; var end = '<li><a href="favoriterank.html">收藏排行榜</a></li>'; var lis = first; //遍历 数组 for (var i = 0; i < data.length; i++) { var li = '<li><a href="route_list.html?cid=' + data[i].cid + '">' + data[i].cname + '</a></li>'; lis += li; } lis+=end; //将lis字符串,设置到ul的html内容中 $("#category").html(lis); }) <!-- 首页导航 --> <div class="navitem"> <ul id="category" class="nav"> <!--通过查询数据库动态的添加--> <!--<li class="nav-active"><a href="index.html">首页</a></li>--> <!--<li><a href="route_list.html">门票</a></li>--> <!--<li><a href="route_list.html">酒店</a></li>--> <!--<li><a href="route_list.html">香港车票</a></li>--> <!--<li><a href="route_list.html">出境游</a></li>--> <!--<li><a href="route_list.html">国内游</a></li>--> <!--<li><a href="route_list.html">港澳游</a></li>--> <!--<li><a href="route_list.html">抱团定制</a></li>--> <!--<li><a href="route_list.html">全球自由行</a></li>--> <!--<li><a href="favoriterank.html">收藏排行榜</a></li>--> </ul> </div>tab_route 存储的就是点击不同的类别后,后面显示的数据信息
tab_category 和 tab_route 表是一对多的关系
通过tab_category表我们可以得到cid,然后通过cid我们就可以查询tab_route表里面的信息
前期分析很重要,我们先把后台代码写通了前台代码自然就简单多了
其实就是用户点击了不同类别的旅游景点信息后,就有一个cid,通过cid我们就可以去查询具体是那个类别的旅游信息,这个时候我们前头可以给服务器说我们需要哪些信息,服务器就返回什么样的信息
服务端:
int totalCount //总记录数int totalPage //总页数int currentPage //当前页码int pageSize //每页显示条数客户端:(发送ajax请求)
currentPage //当前页码pageSize //每页显示条数cid //分页id当前页码 每页显示条数,可以不通过服务器返回,应为这些信息是我们客服端发过去的,但是为了统一操作我们还是通过服务器返回,应为这些信息都是在一个json里面。当我们客服端不给这些信息的时候服务端还可以给默认的值
每次服务端返回的数据只有一页的数据量,但是还包含中的页码、种记录数 、每页显示条数。种页码种记录数是为了填写网页最下面的导航信息
每个旅游景点的详细信息我们封装在 Route 类里面
/** * 旅游线路商品实体类 * 每一个项目的具体信息 */ public class Route implements Serializable { private int rid;//线路id,必输 private String rname;//线路名称,必输 private double price;//价格,必输 private String routeIntroduce;//线路介绍 private String rflag; //是否上架,必输,0代表没有上架,1代表是上架 private String rdate; //上架时间 private String isThemeTour;//是否主题旅游,必输,0代表不是,1代表是 private int count;//收藏数量 private int cid;//所属分类,必输 private String rimage;//缩略图 private int sid;//所属商家 private String sourceId;//抓取数据的来源id private Category category;//所属分类 private Seller seller;//所属商家 private List<RouteImg> routeImgList;//商品详情图片列表 //... }我们用另外一个类(PageBean)来封装所有的信息,不仅包含具体的景点信息还包含有多少个景点,多少页等记录
/** * 分页对象 * 存储了各种页面信息 */ public class PageBean<T> { private int totalCount;//总记录数 private int totalPage;//总页数 private int currentPage;//当前页码 private int pageSize;//每页显示的条数 private List<T> list;//每页显示的数据集合 //... }在前台代码框里面有一个根据线路查询旅游景点的搜索框,我们需要完善这个搜索框
这里的查询和前面的根据cid查询不同类别的旅游线路数据 代码是一模一样的,我们只需要在原来的代码上修改一下即可,增加一个模糊查询,如果我们传给后台的代码中后 cname 我们就模糊查询,否则就是正常的查询即可
<div class="search"> <input id="search_input" name="" type="text" placeholder="请输入路线名称" class="search_input" autocomplete="off"> <a id="search-button" href="javascript:void(0)" class="search-button">搜索</a> </div>我们给搜索按钮绑定一个点击事件,然后获取输入的值,直接修改游览器的地址栏发送请求给 route_list.html 页面即可
//给搜索框绑定单击事件,获取搜索输入框的内容 $("#search-button").click(function () { //线路名称 var rname = $("#search_input").val(); //alert(rname); var cid = getParameter("cid") //alert(cid); //跳转路径 http://localhost:8080/travel_ssm/route_list.html?cid=5,拼接上 rname=xxx location.href = "http://localhost:8080/travel_ssm/route_list.html?cid=" + cid + "&rname=" + rname; })
我这里的查询,是通过MyBatis的动态SQL 写的,当然你也可以拼接字符串执行
<!--int findTotalCount(int cid, String rname);--> <select id="findTotalCount" resultType="int"> <!--取出的值默认两边加上% --> <if test="rname!=null"> <bind name="_rname" value="'%'+rname+'%'"/> </if> select count(*) from tab_route <where> cid = #{cid} <if test="rname!=null"> and rname like #{_rname} </if> </where> </select> <!--# Preparing: select * from tab_route WHERE cid = ? and rname like ? limit ?, ?--> <!--# Parameters: 5(Integer), %null%(String), 30(Integer), 10(Integer)--> <!--limit ? , ? 第一个是重哪里开始,第二个查询的记录条数--> <!--List<Route> findByPage(int cid, int start, int pageSize, String rname);--> <select id="findByPage" resultType="com.bug.domain.route.Route"> <!--<bind name="_rname" value="'%'+rname+'%'"/>--> <if test="rname!=null"> <bind name="_rname" value="'%'+rname+'%'"/> </if> select * from tab_route <where> cid = #{cid} # and rname.length() > 0 <if test="rname!=null"> and rname like #{_rname} </if> limit #{start}, #{pageSize} </where> </select>/** * 分页查询 * 如果有 rname 这个时候我们就需要模糊查询 */ @RequestMapping("/pageQuery") @ResponseBody public PageBean pageQuery(HttpServletRequest request) throws UnsupportedEncodingException { //1.接受参数 String currentPageStr = request.getParameter("currentPage");//当前页数 String pageSizeStr = request.getParameter("pageSize");//查询多少页 String cidStr = request.getParameter("cid");// //接受rname 线路名称 String rname = request.getParameter("rname");//m // System.out.println("rname:\t"+rname); // rname = new String(rname.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); //rname 是中文,发送的还是get请求可能乱码 又有我配置了字符编码过滤器,这里是不可以使用的,不然正常的就会变成乱码 // System.out.println("rname:\t"+rname); System.out.println("rname:\t"+rname); System.out.println("rname 是不是为空:\t"+(rname == null)); if (rname == null || rname.equals("null")) {//没有给他一个空字符串 rname = null; } System.out.println("rname 是不是为空:\t"+(rname == null)); int cid = 0;//类别id //2.处理参数 //在首页 搜索 cid = "null" 会发生类型转换异常 //http://localhost:8080/travel_ssm/route_list.html?cid=null&rname=西安 if (cidStr != null && cidStr.length() > 0 && !cidStr.equals("null")) { 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对象 //4. 将pageBean对象序列化为json,返回 return routeService.pageQuery(cid, currentPage, pageSize, rname); }
分析:
我们抽象了一个 BaseServlet 类,让这个类继承HttpServlet,然后让其他类继承这个类
虽然我是使用的SpringMVC来做的,但是这个方法是一种很好的方法
程序中的 this 的指向是,谁调用就指向的就是谁,看下面的演示代码
父类:
public class Father{ public void service(){ System.out.println(this); } }子类:
public class Son extends Father{ }测试:
@Test public void test() { Son son = new Son(); son.service(); }输出:
com.bug.service.impl.Son@3d012dd
通过上面的代码我们可以定义一个基础的类(BaseServlet ),让他去基础HttpServlet,其他类继承这个类,这个时候当程序调用 service 方法的时候我们就可以通过反射来执行响应的代码
BaseServlet
@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 | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } }解释:上面这个类由于子类没有重写父类的service方法,所有程序会首先执行父类的service方法,这个时候我们可以把请求参数提取出来,this.getClass() 的到的是子类对象,这个时候我们就通过反射的方式去执行子类相应的请求方法
这样做的好处是,当我们的请求参数是什么程序实际上就执行的是什么方法,应为我们子类没有重写父类的service方法,这个时候我们会执行父类的service方法,我们请求的参数是什么最后就会动态的执行子类的什么方法。
这个时候我们就可以把同一个操作放在同一类里面了,如果不这样做的话,下面的每个方法我们都需要写一个类来处理
@WebServlet("/user/*") // /user/add /user/find public class UserServlet extends BaseServlet { /** * 注册功能 */ public void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 省略业务代码 } /** * 查询单个对象 */ public void findOne(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 省略业务代码 } /** * 退出功能 */ public void exit(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 省略业务代码 } /** * 激活功能 */ public void active(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 省略业务代码 } }客户端传递一个 rid 然后重服务器的Session域中取出用户的 uid (没有的话我们uid置为-1反正不可能有这个人),然后在 tab_favorite 表中查询
我是使用的SpringMVC 这个时候我只需要在 web.xml 里面配置过滤器即可
<!-- 3、字符编码过滤器,一定要放在所有过滤器之前 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
